// baltzo_windowstimezoneutil.t.cpp                                   -*-C++-*-
#include <baltzo_windowstimezoneutil.h>

#include <baltzo_timezoneutil.h>
#include <baltzo_testloader.h>
#include <baltzo_defaultzoneinfocache.h>
#include <baltzo_localdatetime.h>

#include <bdlt_datetime.h>

#include <bslma_allocator.h>
#include <bslma_default.h>

#include <bsls_assert.h>
#include <bsls_asserttest.h>

#include <bsl_cstdlib.h>
#include <bsl_iostream.h>

#ifdef BSLS_PLATFORM_OS_WINDOWS
#include <iomanip>
#include <iostream>
#include <windows.h>
#include <wchar.h>
#endif

using namespace BloombergLP;
using namespace bsl;

// ============================================================================
//                              TEST PLAN
// ----------------------------------------------------------------------------
//                              Overview
//                              --------
// The component under test provide a utility for mapping time zone identifiers
// between Zoneinfo and Windows naming systems.  The methods are implemented
// using standard algorithms on two sorted static tables: one mapping Windows
// time-zone identifiers to Zoneinfo time-zone identifiers; the other mapping
// Zoneinfo time-zone identifiers to Windows time-zone identifiers.  These
// tables were semi-mechanically generated from a mapping table obtained from
// `unicode.org`.  As a check on that transformation, the tests here use as a
// reference, a separate copy of the `unicode.org` table, that has been
// minimally transformed into a C-compatible table, `DEFAULT_DATA`.  Each row
// and column has the same data, in the same order as the original
// `unicode.org`.  The only changes has be the conversion of `html` tags to
// double quotes, commas, etc.
//
// ----------------------------------------------------------------------------
// CLASS METHODS
// [ 1] getZoneinfoId(const char **, const char *);
// [ 2] getWindowsTimeZoneId(const char **, const char *);
// ----------------------------------------------------------------------------
// [ 3] MAPPING TABLE COVERAGE
// [ 4] USAGE EXAMPLE
// [-1] WINDOWS PLATFORM CHECKS
//
// ============================================================================
//                    STANDARD BDE ASSERT TEST MACRO
// ----------------------------------------------------------------------------
static int testStatus = 0;
static void aSsErT(int c, const char *s, int i)
{
    if (c) {
        cout << "Error " << __FILE__ << "(" << i << "): " << s
             << "    (failed)" << endl;
        if (testStatus >= 0 && testStatus <= 100) ++testStatus;
    }
}
#define ASSERT(X) { aSsErT(!(X), #X, __LINE__); }

// ============================================================================
//                   STANDARD BDE LOOP-ASSERT TEST MACROS
// ----------------------------------------------------------------------------
#define LOOP_ASSERT(I,X) { \
   if (!(X)) { cout << #I << ": " << I << "\n"; aSsErT(1, #X, __LINE__); }}

#define LOOP2_ASSERT(I,J,X) { \
   if (!(X)) { cout << #I << ": " << I << "\t" << #J << ": " \
              << J << "\n"; aSsErT(1, #X, __LINE__); } }

#define LOOP3_ASSERT(I,J,K,X) { \
   if (!(X)) { cout << #I << ": " << I << "\t" << #J << ": " \
                    << J << "\t" \
                    << #K << ": " << K <<  "\n"; aSsErT(1, #X, __LINE__); } }

#define LOOP4_ASSERT(I,J,K,L,X) { \
   if (!(X)) { cout << #I << ": " << I << "\t" << #J << ": " << J << "\t" << \
       #K << ": " << K << "\t" << #L << ": " << L << "\n"; \
       aSsErT(1, #X, __LINE__); } }

// ============================================================================
//                     SEMI-STANDARD TEST OUTPUT MACROS
// ----------------------------------------------------------------------------
#define P(X) cout << #X " = " << (X) << endl; // Print identifier and value.
#define Q(X) cout << "<| " #X " |>" << endl;  // Quote identifier literally.
#define P_(X) cout << #X " = " << (X) << ", "<< flush; // P(X) without '\n'
#define T_  cout << "\t" << flush;          // Print a tab (w/o newline)
#define L_ __LINE__                           // current Line number

// ============================================================================
//                     NEGATIVE-TEST MACRO ABBREVIATIONS
// ----------------------------------------------------------------------------
#define ASSERT_SAFE_PASS(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_PASS(EXPR)
#define ASSERT_SAFE_FAIL(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_FAIL(EXPR)
#define ASSERT_PASS(EXPR)      BSLS_ASSERTTEST_ASSERT_PASS(EXPR)
#define ASSERT_FAIL(EXPR)      BSLS_ASSERTTEST_ASSERT_FAIL(EXPR)
#define ASSERT_OPT_PASS(EXPR)  BSLS_ASSERTTEST_ASSERT_OPT_PASS(EXPR)
#define ASSERT_OPT_FAIL(EXPR)  BSLS_ASSERTTEST_ASSERT_OPT_FAIL(EXPR)

// ============================================================================
//                   GLOBAL TYPEDEFS/CONSTANTS FOR TESTING
// ----------------------------------------------------------------------------

typedef baltzo::WindowsTimeZoneUtil Obj;

typedef struct DefaultDataRow {
    int         d_line;
    const char *d_windowsId;
    const char *d_region;
    const char *d_zoneinfoId;
} DefaultDataRow;

static const DefaultDataRow DEFAULT_DATA[] = {
      //  +--------------------------------+--------+---------------------+
      //  |Windows Time Zone Identifier    | Region | Zoneinfo Identifier |
      //  +--------------------------------+--------+---------------------+
    { L_,       "AUS Central Standard Time",  "001", "Australia/Darwin"    },
    { L_,       "AUS Eastern Standard Time",  "001", "Australia/Sydney"    },
    { L_,       "Afghanistan Standard Time",  "001", "Asia/Kabul"          },
    { L_,           "Alaskan Standard Time",  "001", "America/Anchorage"   },
    { L_,              "Arab Standard Time",  "001", "Asia/Riyadh"         },
    { L_,           "Arabian Standard Time",  "001", "Asia/Dubai"          },
    { L_,            "Arabic Standard Time",  "001", "Asia/Baghdad"        },
    { L_,         "Argentina Standard Time",  "001", "America/Buenos_Aires"},
    { L_,          "Atlantic Standard Time",  "001", "America/Halifax"     },
    { L_,        "Azerbaijan Standard Time",  "001", "Asia/Baku"           },
    { L_,            "Azores Standard Time",  "001", "Atlantic/Azores"     },
    { L_,             "Bahia Standard Time",  "001", "America/Bahia"       },
    { L_,        "Bangladesh Standard Time",  "001", "Asia/Dhaka"          },
    { L_,    "Canada Central Standard Time",  "001", "America/Regina"      },
    { L_,        "Cape Verde Standard Time",  "001", "Atlantic/Cape_Verde" },
    { L_,          "Caucasus Standard Time",  "001", "Asia/Yerevan"        },
    { L_,    "Cen. Australia Standard Time",  "001", "Australia/Adelaide"  },
    { L_,   "Central America Standard Time",  "001", "America/Guatemala"   },
    { L_,      "Central Asia Standard Time",  "001", "Asia/Almaty"         },
    { L_, "Central Brazilian Standard Time",  "001", "America/Cuiaba"      },
    { L_,    "Central Europe Standard Time",  "001", "Europe/Budapest"     },
    { L_,  "Central European Standard Time",  "001", "Europe/Warsaw"       },
    { L_,   "Central Pacific Standard Time",  "001", "Pacific/Guadalcanal" },
    { L_,           "Central Standard Time",  "001", "America/Chicago"     },
    { L_,  "Central Standard Time (Mexico)",  "001", "America/Mexico_City" },
    { L_,             "China Standard Time",  "001", "Asia/Shanghai"       },
    { L_,          "Dateline Standard Time",  "001", "Etc/GMT+12"          },
    { L_,         "E. Africa Standard Time",  "001", "Africa/Nairobi"      },
    { L_,      "E. Australia Standard Time",  "001", "Australia/Brisbane"  },
    { L_,         "E. Europe Standard Time",  "001", "Asia/Nicosia"        },
    { L_,  "E. South America Standard Time",  "001", "America/Sao_Paulo"   },
    { L_,           "Eastern Standard Time",  "001", "America/New_York"    },
    { L_,             "Egypt Standard Time",  "001", "Africa/Cairo"        },
    { L_,      "Ekaterinburg Standard Time",  "001", "Asia/Yekaterinburg"  },
    { L_,               "FLE Standard Time",  "001", "Europe/Kiev"         },
    { L_,              "Fiji Standard Time",  "001", "Pacific/Fiji"        },
    { L_,               "GMT Standard Time",  "001", "Europe/London"       },
    { L_,               "GTB Standard Time",  "001", "Europe/Bucharest"    },
    { L_,          "Georgian Standard Time",  "001", "Asia/Tbilisi"        },
    { L_,         "Greenland Standard Time",  "001", "America/Godthab"     },
    { L_,         "Greenwich Standard Time",  "001", "Atlantic/Reykjavik"  },
    { L_,          "Hawaiian Standard Time",  "001", "Pacific/Honolulu"    },
    { L_,             "India Standard Time",  "001", "Asia/Kolkata"        },
    { L_,              "Iran Standard Time",  "001", "Asia/Tehran"         },
    { L_,            "Israel Standard Time",  "001", "Asia/Jerusalem"      },
    { L_,            "Jordan Standard Time",  "001", "Asia/Amman"          },
    { L_,       "Kaliningrad Standard Time",  "001", "Europe/Kaliningrad"  },
    { L_,             "Korea Standard Time",  "001", "Asia/Seoul"          },
    { L_,           "Magadan Standard Time",  "001", "Asia/Magadan"        },
    { L_,         "Mauritius Standard Time",  "001", "Indian/Mauritius"    },
    { L_,       "Middle East Standard Time",  "001", "Asia/Beirut"         },
    { L_,        "Montevideo Standard Time",  "001", "America/Montevideo"  },
    { L_,           "Morocco Standard Time",  "001", "Africa/Casablanca"   },
    { L_,          "Mountain Standard Time",  "001", "America/Denver"      },
    { L_, "Mountain Standard Time (Mexico)",  "001", "America/Chihuahua"   },
    { L_,           "Myanmar Standard Time",  "001", "Asia/Rangoon"        },
    { L_,   "N. Central Asia Standard Time",  "001", "Asia/Novosibirsk"    },
    { L_,           "Namibia Standard Time",  "001", "Africa/Windhoek"     },
    { L_,             "Nepal Standard Time",  "001", "Asia/Katmandu"       },
    { L_,       "New Zealand Standard Time",  "001", "Pacific/Auckland"    },
    { L_,      "Newfoundland Standard Time",  "001", "America/St_Johns"    },
    { L_,   "North Asia East Standard Time",  "001", "Asia/Irkutsk"        },
    { L_,        "North Asia Standard Time",  "001", "Asia/Krasnoyarsk"    },
    { L_,        "Pacific SA Standard Time",  "001", "America/Santiago"    },
    { L_,           "Pacific Standard Time",  "001", "America/Los_Angeles" },
    { L_,  "Pacific Standard Time (Mexico)",  "001", "America/Santa_Isabel"},
    { L_,          "Pakistan Standard Time",  "001", "Asia/Karachi"        },
    { L_,          "Paraguay Standard Time",  "001", "America/Asuncion"    },
    { L_,           "Romance Standard Time",  "001", "Europe/Paris"        },
    { L_,           "Russian Standard Time",  "001", "Europe/Moscow"       },
    { L_,        "SA Eastern Standard Time",  "001", "America/Cayenne"     },
    { L_,        "SA Pacific Standard Time",  "001", "America/Bogota"      },
    { L_,        "SA Western Standard Time",  "001", "America/La_Paz"      },
    { L_,           "SE Asia Standard Time",  "001", "Asia/Bangkok"        },
    { L_,             "Samoa Standard Time",  "001", "Pacific/Apia"        },
    { L_,         "Singapore Standard Time",  "001", "Asia/Singapore"      },
    { L_,      "South Africa Standard Time",  "001", "Africa/Johannesburg" },
    { L_,         "Sri Lanka Standard Time",  "001", "Asia/Colombo"        },
    { L_,             "Syria Standard Time",  "001", "Asia/Damascus"       },
    { L_,            "Taipei Standard Time",  "001", "Asia/Taipei"         },
    { L_,          "Tasmania Standard Time",  "001", "Australia/Hobart"    },
    { L_,             "Tokyo Standard Time",  "001", "Asia/Tokyo"          },
    { L_,             "Tonga Standard Time",  "001", "Pacific/Tongatapu"   },
    { L_,            "Turkey Standard Time",  "001", "Europe/Istanbul"     },
    { L_,        "US Eastern Standard Time",  "001", "America/Indianapolis"},
    { L_,       "US Mountain Standard Time",  "001", "America/Phoenix"     },
    { L_,                             "UTC",  "001", "Etc/GMT"             },
    { L_,                          "UTC+12",  "001", "Etc/GMT-12"          },
    { L_,                          "UTC-02",  "001", "Etc/GMT+2"           },
    { L_,                          "UTC-11",  "001", "Etc/GMT+11"          },
    { L_,       "Ulaanbaatar Standard Time",  "001", "Asia/Ulaanbaatar"    },
    { L_,         "Venezuela Standard Time",  "001", "America/Caracas"     },
    { L_,       "Vladivostok Standard Time",  "001", "Asia/Vladivostok"    },
    { L_,      "W. Australia Standard Time",  "001", "Australia/Perth"     },
    { L_, "W. Central Africa Standard Time",  "001", "Africa/Lagos"        },
    { L_,         "W. Europe Standard Time",  "001", "Europe/Berlin"       },
    { L_,         "West Asia Standard Time",  "001", "Asia/Tashkent"       },
    { L_,      "West Pacific Standard Time",  "001", "Pacific/Port_Moresby"},
    { L_,           "Yakutsk Standard Time",  "001", "Asia/Yakutsk"        }
      //  +--------------------------------+--------+---------------------+
};
const int DEFAULT_NUM_DATA = sizeof DEFAULT_DATA / sizeof *DEFAULT_DATA;

// ============================================================================
//                            TEST TIME ZONE DATA
// ----------------------------------------------------------------------------

// America/New_York
static const unsigned char AMERICA_NEW_YORK_DATA[] = {
    0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
    0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb,
    0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x9e, 0xa6, 0x1e, 0x70,
    0x9f, 0xba, 0xeb, 0x60, 0xa0, 0x86, 0x00, 0x70, 0xa1, 0x9a, 0xcd, 0x60,
    0xa2, 0x65, 0xe2, 0x70, 0xa3, 0x83, 0xe9, 0xe0, 0xa4, 0x6a, 0xae, 0x70,
    0xa5, 0x35, 0xa7, 0x60, 0xa6, 0x53, 0xca, 0xf0, 0xa7, 0x15, 0x89, 0x60,
    0xa8, 0x33, 0xac, 0xf0, 0xa8, 0xfe, 0xa5, 0xe0, 0xaa, 0x13, 0x8e, 0xf0,
    0xaa, 0xde, 0x87, 0xe0, 0xab, 0xf3, 0x70, 0xf0, 0xac, 0xbe, 0x69, 0xe0,
    0xad, 0xd3, 0x52, 0xf0, 0xae, 0x9e, 0x4b, 0xe0, 0xaf, 0xb3, 0x34, 0xf0,
    0xb0, 0x7e, 0x2d, 0xe0, 0xb1, 0x9c, 0x51, 0x70, 0xb2, 0x67, 0x4a, 0x60,
    0xb3, 0x7c, 0x33, 0x70, 0xb4, 0x47, 0x2c, 0x60, 0xb5, 0x5c, 0x15, 0x70,
    0xb6, 0x27, 0x0e, 0x60, 0xb7, 0x3b, 0xf7, 0x70, 0xb8, 0x06, 0xf0, 0x60,
    0xb9, 0x1b, 0xd9, 0x70, 0xb9, 0xe6, 0xd2, 0x60, 0xbb, 0x04, 0xf5, 0xf0,
    0xbb, 0xc6, 0xb4, 0x60, 0xbc, 0xe4, 0xd7, 0xf0, 0xbd, 0xaf, 0xd0, 0xe0,
    0xbe, 0xc4, 0xb9, 0xf0, 0xbf, 0x8f, 0xb2, 0xe0, 0xc0, 0xa4, 0x9b, 0xf0,
    0xc1, 0x6f, 0x94, 0xe0, 0xc2, 0x84, 0x7d, 0xf0, 0xc3, 0x4f, 0x76, 0xe0,
    0xc4, 0x64, 0x5f, 0xf0, 0xc5, 0x2f, 0x58, 0xe0, 0xc6, 0x4d, 0x7c, 0x70,
    0xc7, 0x0f, 0x3a, 0xe0, 0xc8, 0x2d, 0x5e, 0x70, 0xc8, 0xf8, 0x57, 0x60,
    0xca, 0x0d, 0x40, 0x70, 0xca, 0xd8, 0x39, 0x60, 0xcb, 0x88, 0xf0, 0x70,
    0xd2, 0x23, 0xf4, 0x70, 0xd2, 0x60, 0xfb, 0xe0, 0xd3, 0x75, 0xe4, 0xf0,
    0xd4, 0x40, 0xdd, 0xe0, 0xd5, 0x55, 0xc6, 0xf0, 0xd6, 0x20, 0xbf, 0xe0,
    0xd7, 0x35, 0xa8, 0xf0, 0xd8, 0x00, 0xa1, 0xe0, 0xd9, 0x15, 0x8a, 0xf0,
    0xd9, 0xe0, 0x83, 0xe0, 0xda, 0xfe, 0xa7, 0x70, 0xdb, 0xc0, 0x65, 0xe0,
    0xdc, 0xde, 0x89, 0x70, 0xdd, 0xa9, 0x82, 0x60, 0xde, 0xbe, 0x6b, 0x70,
    0xdf, 0x89, 0x64, 0x60, 0xe0, 0x9e, 0x4d, 0x70, 0xe1, 0x69, 0x46, 0x60,
    0xe2, 0x7e, 0x2f, 0x70, 0xe3, 0x49, 0x28, 0x60, 0xe4, 0x5e, 0x11, 0x70,
    0xe5, 0x57, 0x2e, 0xe0, 0xe6, 0x47, 0x2d, 0xf0, 0xe7, 0x37, 0x10, 0xe0,
    0xe8, 0x27, 0x0f, 0xf0, 0xe9, 0x16, 0xf2, 0xe0, 0xea, 0x06, 0xf1, 0xf0,
    0xea, 0xf6, 0xd4, 0xe0, 0xeb, 0xe6, 0xd3, 0xf0, 0xec, 0xd6, 0xb6, 0xe0,
    0xed, 0xc6, 0xb5, 0xf0, 0xee, 0xbf, 0xd3, 0x60, 0xef, 0xaf, 0xd2, 0x70,
    0xf0, 0x9f, 0xb5, 0x60, 0xf1, 0x8f, 0xb4, 0x70, 0xf2, 0x7f, 0x97, 0x60,
    0xf3, 0x6f, 0x96, 0x70, 0xf4, 0x5f, 0x79, 0x60, 0xf5, 0x4f, 0x78, 0x70,
    0xf6, 0x3f, 0x5b, 0x60, 0xf7, 0x2f, 0x5a, 0x70, 0xf8, 0x28, 0x77, 0xe0,
    0xf9, 0x0f, 0x3c, 0x70, 0xfa, 0x08, 0x59, 0xe0, 0xfa, 0xf8, 0x58, 0xf0,
    0xfb, 0xe8, 0x3b, 0xe0, 0xfc, 0xd8, 0x3a, 0xf0, 0xfd, 0xc8, 0x1d, 0xe0,
    0xfe, 0xb8, 0x1c, 0xf0, 0xff, 0xa7, 0xff, 0xe0, 0x00, 0x97, 0xfe, 0xf0,
    0x01, 0x87, 0xe1, 0xe0, 0x02, 0x77, 0xe0, 0xf0, 0x03, 0x70, 0xfe, 0x60,
    0x04, 0x60, 0xfd, 0x70, 0x05, 0x50, 0xe0, 0x60, 0x06, 0x40, 0xdf, 0x70,
    0x07, 0x30, 0xc2, 0x60, 0x07, 0x8d, 0x19, 0x70, 0x09, 0x10, 0xa4, 0x60,
    0x09, 0xad, 0x94, 0xf0, 0x0a, 0xf0, 0x86, 0x60, 0x0b, 0xe0, 0x85, 0x70,
    0x0c, 0xd9, 0xa2, 0xe0, 0x0d, 0xc0, 0x67, 0x70, 0x0e, 0xb9, 0x84, 0xe0,
    0x0f, 0xa9, 0x83, 0xf0, 0x10, 0x99, 0x66, 0xe0, 0x11, 0x89, 0x65, 0xf0,
    0x12, 0x79, 0x48, 0xe0, 0x13, 0x69, 0x47, 0xf0, 0x14, 0x59, 0x2a, 0xe0,
    0x15, 0x49, 0x29, 0xf0, 0x16, 0x39, 0x0c, 0xe0, 0x17, 0x29, 0x0b, 0xf0,
    0x18, 0x22, 0x29, 0x60, 0x19, 0x08, 0xed, 0xf0, 0x1a, 0x02, 0x0b, 0x60,
    0x1a, 0xf2, 0x0a, 0x70, 0x1b, 0xe1, 0xed, 0x60, 0x1c, 0xd1, 0xec, 0x70,
    0x1d, 0xc1, 0xcf, 0x60, 0x1e, 0xb1, 0xce, 0x70, 0x1f, 0xa1, 0xb1, 0x60,
    0x20, 0x76, 0x00, 0xf0, 0x21, 0x81, 0x93, 0x60, 0x22, 0x55, 0xe2, 0xf0,
    0x23, 0x6a, 0xaf, 0xe0, 0x24, 0x35, 0xc4, 0xf0, 0x25, 0x4a, 0x91, 0xe0,
    0x26, 0x15, 0xa6, 0xf0, 0x27, 0x2a, 0x73, 0xe0, 0x27, 0xfe, 0xc3, 0x70,
    0x29, 0x0a, 0x55, 0xe0, 0x29, 0xde, 0xa5, 0x70, 0x2a, 0xea, 0x37, 0xe0,
    0x2b, 0xbe, 0x87, 0x70, 0x2c, 0xd3, 0x54, 0x60, 0x2d, 0x9e, 0x69, 0x70,
    0x2e, 0xb3, 0x36, 0x60, 0x2f, 0x7e, 0x4b, 0x70, 0x30, 0x93, 0x18, 0x60,
    0x31, 0x67, 0x67, 0xf0, 0x32, 0x72, 0xfa, 0x60, 0x33, 0x47, 0x49, 0xf0,
    0x34, 0x52, 0xdc, 0x60, 0x35, 0x27, 0x2b, 0xf0, 0x36, 0x32, 0xbe, 0x60,
    0x37, 0x07, 0x0d, 0xf0, 0x38, 0x1b, 0xda, 0xe0, 0x38, 0xe6, 0xef, 0xf0,
    0x39, 0xfb, 0xbc, 0xe0, 0x3a, 0xc6, 0xd1, 0xf0, 0x3b, 0xdb, 0x9e, 0xe0,
    0x3c, 0xaf, 0xee, 0x70, 0x3d, 0xbb, 0x80, 0xe0, 0x3e, 0x8f, 0xd0, 0x70,
    0x3f, 0x9b, 0x62, 0xe0, 0x40, 0x6f, 0xb2, 0x70, 0x41, 0x84, 0x7f, 0x60,
    0x42, 0x4f, 0x94, 0x70, 0x43, 0x64, 0x61, 0x60, 0x44, 0x2f, 0x76, 0x70,
    0x45, 0x44, 0x43, 0x60, 0x45, 0xf3, 0xa8, 0xf0, 0x47, 0x2d, 0x5f, 0xe0,
    0x47, 0xd3, 0x8a, 0xf0, 0x49, 0x0d, 0x41, 0xe0, 0x49, 0xb3, 0x6c, 0xf0,
    0x4a, 0xed, 0x23, 0xe0, 0x4b, 0x9c, 0x89, 0x70, 0x4c, 0xd6, 0x40, 0x60,
    0x4d, 0x7c, 0x6b, 0x70, 0x4e, 0xb6, 0x22, 0x60, 0x4f, 0x5c, 0x4d, 0x70,
    0x50, 0x96, 0x04, 0x60, 0x51, 0x3c, 0x2f, 0x70, 0x52, 0x75, 0xe6, 0x60,
    0x53, 0x1c, 0x11, 0x70, 0x54, 0x55, 0xc8, 0x60, 0x54, 0xfb, 0xf3, 0x70,
    0x56, 0x35, 0xaa, 0x60, 0x56, 0xe5, 0x0f, 0xf0, 0x58, 0x1e, 0xc6, 0xe0,
    0x58, 0xc4, 0xf1, 0xf0, 0x59, 0xfe, 0xa8, 0xe0, 0x5a, 0xa4, 0xd3, 0xf0,
    0x5b, 0xde, 0x8a, 0xe0, 0x5c, 0x84, 0xb5, 0xf0, 0x5d, 0xbe, 0x6c, 0xe0,
    0x5e, 0x64, 0x97, 0xf0, 0x5f, 0x9e, 0x4e, 0xe0, 0x60, 0x4d, 0xb4, 0x70,
    0x61, 0x87, 0x6b, 0x60, 0x62, 0x2d, 0x96, 0x70, 0x63, 0x67, 0x4d, 0x60,
    0x64, 0x0d, 0x78, 0x70, 0x65, 0x47, 0x2f, 0x60, 0x65, 0xed, 0x5a, 0x70,
    0x67, 0x27, 0x11, 0x60, 0x67, 0xcd, 0x3c, 0x70, 0x69, 0x06, 0xf3, 0x60,
    0x69, 0xad, 0x1e, 0x70, 0x6a, 0xe6, 0xd5, 0x60, 0x6b, 0x96, 0x3a, 0xf0,
    0x6c, 0xcf, 0xf1, 0xe0, 0x6d, 0x76, 0x1c, 0xf0, 0x6e, 0xaf, 0xd3, 0xe0,
    0x6f, 0x55, 0xfe, 0xf0, 0x70, 0x8f, 0xb5, 0xe0, 0x71, 0x35, 0xe0, 0xf0,
    0x72, 0x6f, 0x97, 0xe0, 0x73, 0x15, 0xc2, 0xf0, 0x74, 0x4f, 0x79, 0xe0,
    0x74, 0xfe, 0xdf, 0x70, 0x76, 0x38, 0x96, 0x60, 0x76, 0xde, 0xc1, 0x70,
    0x78, 0x18, 0x78, 0x60, 0x78, 0xbe, 0xa3, 0x70, 0x79, 0xf8, 0x5a, 0x60,
    0x7a, 0x9e, 0x85, 0x70, 0x7b, 0xd8, 0x3c, 0x60, 0x7c, 0x7e, 0x67, 0x70,
    0x7d, 0xb8, 0x1e, 0x60, 0x7e, 0x5e, 0x49, 0x70, 0x7f, 0x98, 0x00, 0x60,
    0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
    0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
    0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
    0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
    0x02, 0x03, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xff, 0xff, 0xc7, 0xc0, 0x01,
    0x00, 0xff, 0xff, 0xb9, 0xb0, 0x00, 0x04, 0xff, 0xff, 0xc7, 0xc0, 0x01,
    0x08, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x0c, 0x45, 0x44, 0x54, 0x00, 0x45,
    0x53, 0x54, 0x00, 0x45, 0x57, 0x54, 0x00, 0x45, 0x50, 0x54, 0x00, 0x00,
    0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x54, 0x5a, 0x69, 0x66, 0x32,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x05, 0x00,
    0x00, 0x00, 0x14, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x03, 0xf0, 0x90, 0xff,
    0xff, 0xff, 0xff, 0x9e, 0xa6, 0x1e, 0x70, 0xff, 0xff, 0xff, 0xff, 0x9f,
    0xba, 0xeb, 0x60, 0xff, 0xff, 0xff, 0xff, 0xa0, 0x86, 0x00, 0x70, 0xff,
    0xff, 0xff, 0xff, 0xa1, 0x9a, 0xcd, 0x60, 0xff, 0xff, 0xff, 0xff, 0xa2,
    0x65, 0xe2, 0x70, 0xff, 0xff, 0xff, 0xff, 0xa3, 0x83, 0xe9, 0xe0, 0xff,
    0xff, 0xff, 0xff, 0xa4, 0x6a, 0xae, 0x70, 0xff, 0xff, 0xff, 0xff, 0xa5,
    0x35, 0xa7, 0x60, 0xff, 0xff, 0xff, 0xff, 0xa6, 0x53, 0xca, 0xf0, 0xff,
    0xff, 0xff, 0xff, 0xa7, 0x15, 0x89, 0x60, 0xff, 0xff, 0xff, 0xff, 0xa8,
    0x33, 0xac, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xa8, 0xfe, 0xa5, 0xe0, 0xff,
    0xff, 0xff, 0xff, 0xaa, 0x13, 0x8e, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xaa,
    0xde, 0x87, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xab, 0xf3, 0x70, 0xf0, 0xff,
    0xff, 0xff, 0xff, 0xac, 0xbe, 0x69, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xad,
    0xd3, 0x52, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xae, 0x9e, 0x4b, 0xe0, 0xff,
    0xff, 0xff, 0xff, 0xaf, 0xb3, 0x34, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xb0,
    0x7e, 0x2d, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x9c, 0x51, 0x70, 0xff,
    0xff, 0xff, 0xff, 0xb2, 0x67, 0x4a, 0x60, 0xff, 0xff, 0xff, 0xff, 0xb3,
    0x7c, 0x33, 0x70, 0xff, 0xff, 0xff, 0xff, 0xb4, 0x47, 0x2c, 0x60, 0xff,
    0xff, 0xff, 0xff, 0xb5, 0x5c, 0x15, 0x70, 0xff, 0xff, 0xff, 0xff, 0xb6,
    0x27, 0x0e, 0x60, 0xff, 0xff, 0xff, 0xff, 0xb7, 0x3b, 0xf7, 0x70, 0xff,
    0xff, 0xff, 0xff, 0xb8, 0x06, 0xf0, 0x60, 0xff, 0xff, 0xff, 0xff, 0xb9,
    0x1b, 0xd9, 0x70, 0xff, 0xff, 0xff, 0xff, 0xb9, 0xe6, 0xd2, 0x60, 0xff,
    0xff, 0xff, 0xff, 0xbb, 0x04, 0xf5, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xbb,
    0xc6, 0xb4, 0x60, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe4, 0xd7, 0xf0, 0xff,
    0xff, 0xff, 0xff, 0xbd, 0xaf, 0xd0, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xbe,
    0xc4, 0xb9, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x8f, 0xb2, 0xe0, 0xff,
    0xff, 0xff, 0xff, 0xc0, 0xa4, 0x9b, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xc1,
    0x6f, 0x94, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x84, 0x7d, 0xf0, 0xff,
    0xff, 0xff, 0xff, 0xc3, 0x4f, 0x76, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xc4,
    0x64, 0x5f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xc5, 0x2f, 0x58, 0xe0, 0xff,
    0xff, 0xff, 0xff, 0xc6, 0x4d, 0x7c, 0x70, 0xff, 0xff, 0xff, 0xff, 0xc7,
    0x0f, 0x3a, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x2d, 0x5e, 0x70, 0xff,
    0xff, 0xff, 0xff, 0xc8, 0xf8, 0x57, 0x60, 0xff, 0xff, 0xff, 0xff, 0xca,
    0x0d, 0x40, 0x70, 0xff, 0xff, 0xff, 0xff, 0xca, 0xd8, 0x39, 0x60, 0xff,
    0xff, 0xff, 0xff, 0xcb, 0x88, 0xf0, 0x70, 0xff, 0xff, 0xff, 0xff, 0xd2,
    0x23, 0xf4, 0x70, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x60, 0xfb, 0xe0, 0xff,
    0xff, 0xff, 0xff, 0xd3, 0x75, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xd4,
    0x40, 0xdd, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xd5, 0x55, 0xc6, 0xf0, 0xff,
    0xff, 0xff, 0xff, 0xd6, 0x20, 0xbf, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xd7,
    0x35, 0xa8, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xd8, 0x00, 0xa1, 0xe0, 0xff,
    0xff, 0xff, 0xff, 0xd9, 0x15, 0x8a, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xd9,
    0xe0, 0x83, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfe, 0xa7, 0x70, 0xff,
    0xff, 0xff, 0xff, 0xdb, 0xc0, 0x65, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xdc,
    0xde, 0x89, 0x70, 0xff, 0xff, 0xff, 0xff, 0xdd, 0xa9, 0x82, 0x60, 0xff,
    0xff, 0xff, 0xff, 0xde, 0xbe, 0x6b, 0x70, 0xff, 0xff, 0xff, 0xff, 0xdf,
    0x89, 0x64, 0x60, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x9e, 0x4d, 0x70, 0xff,
    0xff, 0xff, 0xff, 0xe1, 0x69, 0x46, 0x60, 0xff, 0xff, 0xff, 0xff, 0xe2,
    0x7e, 0x2f, 0x70, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x49, 0x28, 0x60, 0xff,
    0xff, 0xff, 0xff, 0xe4, 0x5e, 0x11, 0x70, 0xff, 0xff, 0xff, 0xff, 0xe5,
    0x57, 0x2e, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x47, 0x2d, 0xf0, 0xff,
    0xff, 0xff, 0xff, 0xe7, 0x37, 0x10, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xe8,
    0x27, 0x0f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x16, 0xf2, 0xe0, 0xff,
    0xff, 0xff, 0xff, 0xea, 0x06, 0xf1, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xea,
    0xf6, 0xd4, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xe6, 0xd3, 0xf0, 0xff,
    0xff, 0xff, 0xff, 0xec, 0xd6, 0xb6, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xed,
    0xc6, 0xb5, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xee, 0xbf, 0xd3, 0x60, 0xff,
    0xff, 0xff, 0xff, 0xef, 0xaf, 0xd2, 0x70, 0xff, 0xff, 0xff, 0xff, 0xf0,
    0x9f, 0xb5, 0x60, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x8f, 0xb4, 0x70, 0xff,
    0xff, 0xff, 0xff, 0xf2, 0x7f, 0x97, 0x60, 0xff, 0xff, 0xff, 0xff, 0xf3,
    0x6f, 0x96, 0x70, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x5f, 0x79, 0x60, 0xff,
    0xff, 0xff, 0xff, 0xf5, 0x4f, 0x78, 0x70, 0xff, 0xff, 0xff, 0xff, 0xf6,
    0x3f, 0x5b, 0x60, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x2f, 0x5a, 0x70, 0xff,
    0xff, 0xff, 0xff, 0xf8, 0x28, 0x77, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xf9,
    0x0f, 0x3c, 0x70, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x08, 0x59, 0xe0, 0xff,
    0xff, 0xff, 0xff, 0xfa, 0xf8, 0x58, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xfb,
    0xe8, 0x3b, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xd8, 0x3a, 0xf0, 0xff,
    0xff, 0xff, 0xff, 0xfd, 0xc8, 0x1d, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xfe,
    0xb8, 0x1c, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0xff, 0xe0, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x97, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x87, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x77, 0xe0, 0xf0, 0x00,
    0x00, 0x00, 0x00, 0x03, 0x70, 0xfe, 0x60, 0x00, 0x00, 0x00, 0x00, 0x04,
    0x60, 0xfd, 0x70, 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0xe0, 0x60, 0x00,
    0x00, 0x00, 0x00, 0x06, 0x40, 0xdf, 0x70, 0x00, 0x00, 0x00, 0x00, 0x07,
    0x30, 0xc2, 0x60, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8d, 0x19, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x09, 0x10, 0xa4, 0x60, 0x00, 0x00, 0x00, 0x00, 0x09,
    0xad, 0x94, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xf0, 0x86, 0x60, 0x00,
    0x00, 0x00, 0x00, 0x0b, 0xe0, 0x85, 0x70, 0x00, 0x00, 0x00, 0x00, 0x0c,
    0xd9, 0xa2, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xc0, 0x67, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x0e, 0xb9, 0x84, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x0f,
    0xa9, 0x83, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x66, 0xe0, 0x00,
    0x00, 0x00, 0x00, 0x11, 0x89, 0x65, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x12,
    0x79, 0x48, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x13, 0x69, 0x47, 0xf0, 0x00,
    0x00, 0x00, 0x00, 0x14, 0x59, 0x2a, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x15,
    0x49, 0x29, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x39, 0x0c, 0xe0, 0x00,
    0x00, 0x00, 0x00, 0x17, 0x29, 0x0b, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x18,
    0x22, 0x29, 0x60, 0x00, 0x00, 0x00, 0x00, 0x19, 0x08, 0xed, 0xf0, 0x00,
    0x00, 0x00, 0x00, 0x1a, 0x02, 0x0b, 0x60, 0x00, 0x00, 0x00, 0x00, 0x1a,
    0xf2, 0x0a, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe1, 0xed, 0x60, 0x00,
    0x00, 0x00, 0x00, 0x1c, 0xd1, 0xec, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1d,
    0xc1, 0xcf, 0x60, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xb1, 0xce, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x1f, 0xa1, 0xb1, 0x60, 0x00, 0x00, 0x00, 0x00, 0x20,
    0x76, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x21, 0x81, 0x93, 0x60, 0x00,
    0x00, 0x00, 0x00, 0x22, 0x55, 0xe2, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x23,
    0x6a, 0xaf, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x35, 0xc4, 0xf0, 0x00,
    0x00, 0x00, 0x00, 0x25, 0x4a, 0x91, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x26,
    0x15, 0xa6, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x27, 0x2a, 0x73, 0xe0, 0x00,
    0x00, 0x00, 0x00, 0x27, 0xfe, 0xc3, 0x70, 0x00, 0x00, 0x00, 0x00, 0x29,
    0x0a, 0x55, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x29, 0xde, 0xa5, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x2a, 0xea, 0x37, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x2b,
    0xbe, 0x87, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd3, 0x54, 0x60, 0x00,
    0x00, 0x00, 0x00, 0x2d, 0x9e, 0x69, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2e,
    0xb3, 0x36, 0x60, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x7e, 0x4b, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x30, 0x93, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, 0x31,
    0x67, 0x67, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0xfa, 0x60, 0x00,
    0x00, 0x00, 0x00, 0x33, 0x47, 0x49, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x34,
    0x52, 0xdc, 0x60, 0x00, 0x00, 0x00, 0x00, 0x35, 0x27, 0x2b, 0xf0, 0x00,
    0x00, 0x00, 0x00, 0x36, 0x32, 0xbe, 0x60, 0x00, 0x00, 0x00, 0x00, 0x37,
    0x07, 0x0d, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b, 0xda, 0xe0, 0x00,
    0x00, 0x00, 0x00, 0x38, 0xe6, 0xef, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x39,
    0xfb, 0xbc, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x3a, 0xc6, 0xd1, 0xf0, 0x00,
    0x00, 0x00, 0x00, 0x3b, 0xdb, 0x9e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x3c,
    0xaf, 0xee, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xbb, 0x80, 0xe0, 0x00,
    0x00, 0x00, 0x00, 0x3e, 0x8f, 0xd0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3f,
    0x9b, 0x62, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6f, 0xb2, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x41, 0x84, 0x7f, 0x60, 0x00, 0x00, 0x00, 0x00, 0x42,
    0x4f, 0x94, 0x70, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x61, 0x60, 0x00,
    0x00, 0x00, 0x00, 0x44, 0x2f, 0x76, 0x70, 0x00, 0x00, 0x00, 0x00, 0x45,
    0x44, 0x43, 0x60, 0x00, 0x00, 0x00, 0x00, 0x45, 0xf3, 0xa8, 0xf0, 0x00,
    0x00, 0x00, 0x00, 0x47, 0x2d, 0x5f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x47,
    0xd3, 0x8a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x49, 0x0d, 0x41, 0xe0, 0x00,
    0x00, 0x00, 0x00, 0x49, 0xb3, 0x6c, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x4a,
    0xed, 0x23, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x9c, 0x89, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x4c, 0xd6, 0x40, 0x60, 0x00, 0x00, 0x00, 0x00, 0x4d,
    0x7c, 0x6b, 0x70, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xb6, 0x22, 0x60, 0x00,
    0x00, 0x00, 0x00, 0x4f, 0x5c, 0x4d, 0x70, 0x00, 0x00, 0x00, 0x00, 0x50,
    0x96, 0x04, 0x60, 0x00, 0x00, 0x00, 0x00, 0x51, 0x3c, 0x2f, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x52, 0x75, 0xe6, 0x60, 0x00, 0x00, 0x00, 0x00, 0x53,
    0x1c, 0x11, 0x70, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0xc8, 0x60, 0x00,
    0x00, 0x00, 0x00, 0x54, 0xfb, 0xf3, 0x70, 0x00, 0x00, 0x00, 0x00, 0x56,
    0x35, 0xaa, 0x60, 0x00, 0x00, 0x00, 0x00, 0x56, 0xe5, 0x0f, 0xf0, 0x00,
    0x00, 0x00, 0x00, 0x58, 0x1e, 0xc6, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x58,
    0xc4, 0xf1, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x59, 0xfe, 0xa8, 0xe0, 0x00,
    0x00, 0x00, 0x00, 0x5a, 0xa4, 0xd3, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x5b,
    0xde, 0x8a, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x84, 0xb5, 0xf0, 0x00,
    0x00, 0x00, 0x00, 0x5d, 0xbe, 0x6c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x5e,
    0x64, 0x97, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x9e, 0x4e, 0xe0, 0x00,
    0x00, 0x00, 0x00, 0x60, 0x4d, 0xb4, 0x70, 0x00, 0x00, 0x00, 0x00, 0x61,
    0x87, 0x6b, 0x60, 0x00, 0x00, 0x00, 0x00, 0x62, 0x2d, 0x96, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x63, 0x67, 0x4d, 0x60, 0x00, 0x00, 0x00, 0x00, 0x64,
    0x0d, 0x78, 0x70, 0x00, 0x00, 0x00, 0x00, 0x65, 0x47, 0x2f, 0x60, 0x00,
    0x00, 0x00, 0x00, 0x65, 0xed, 0x5a, 0x70, 0x00, 0x00, 0x00, 0x00, 0x67,
    0x27, 0x11, 0x60, 0x00, 0x00, 0x00, 0x00, 0x67, 0xcd, 0x3c, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x69, 0x06, 0xf3, 0x60, 0x00, 0x00, 0x00, 0x00, 0x69,
    0xad, 0x1e, 0x70, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xe6, 0xd5, 0x60, 0x00,
    0x00, 0x00, 0x00, 0x6b, 0x96, 0x3a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x6c,
    0xcf, 0xf1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x76, 0x1c, 0xf0, 0x00,
    0x00, 0x00, 0x00, 0x6e, 0xaf, 0xd3, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x6f,
    0x55, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8f, 0xb5, 0xe0, 0x00,
    0x00, 0x00, 0x00, 0x71, 0x35, 0xe0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x72,
    0x6f, 0x97, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x73, 0x15, 0xc2, 0xf0, 0x00,
    0x00, 0x00, 0x00, 0x74, 0x4f, 0x79, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x74,
    0xfe, 0xdf, 0x70, 0x00, 0x00, 0x00, 0x00, 0x76, 0x38, 0x96, 0x60, 0x00,
    0x00, 0x00, 0x00, 0x76, 0xde, 0xc1, 0x70, 0x00, 0x00, 0x00, 0x00, 0x78,
    0x18, 0x78, 0x60, 0x00, 0x00, 0x00, 0x00, 0x78, 0xbe, 0xa3, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x79, 0xf8, 0x5a, 0x60, 0x00, 0x00, 0x00, 0x00, 0x7a,
    0x9e, 0x85, 0x70, 0x00, 0x00, 0x00, 0x00, 0x7b, 0xd8, 0x3c, 0x60, 0x00,
    0x00, 0x00, 0x00, 0x7c, 0x7e, 0x67, 0x70, 0x00, 0x00, 0x00, 0x00, 0x7d,
    0xb8, 0x1e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x5e, 0x49, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x7f, 0x98, 0x00, 0x60, 0x02, 0x01, 0x02, 0x01, 0x02,
    0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
    0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
    0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
    0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
    0x02, 0x01, 0x02, 0xff, 0xff, 0xba, 0x9e, 0x00, 0x00, 0xff, 0xff, 0xc7,
    0xc0, 0x01, 0x04, 0xff, 0xff, 0xb9, 0xb0, 0x00, 0x08, 0xff, 0xff, 0xc7,
    0xc0, 0x01, 0x0c, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x10, 0x4c, 0x4d, 0x54,
    0x00, 0x45, 0x44, 0x54, 0x00, 0x45, 0x53, 0x54, 0x00, 0x45, 0x57, 0x54,
    0x00, 0x45, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
    0x00, 0x00, 0x01, 0x0a, 0x45, 0x53, 0x54, 0x35, 0x45, 0x44, 0x54, 0x2c,
    0x4d, 0x33, 0x2e, 0x32, 0x2e, 0x30, 0x2c, 0x4d, 0x31, 0x31, 0x2e, 0x31,
    0x2e, 0x30, 0x0a
};

// GMT
static const unsigned char GMT_DATA[] = {
    0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x47, 0x4d, 0x54, 0x00, 0x00, 0x00, 0x54, 0x5a, 0x69, 0x66,
    0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4d,
    0x54, 0x00, 0x00, 0x00, 0x0a, 0x47, 0x4d, 0x54, 0x30, 0x0a,
};

// Europe/Rome
static const unsigned char EUROPE_ROME_DATA[] = {
    0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
    0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,
    0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x09, 0x9b, 0x37, 0xa6, 0xf0,
    0x9b, 0xd5, 0xda, 0xf0, 0x9c, 0xc5, 0xcb, 0xf0, 0x9d, 0xb5, 0xbc, 0xf0,
    0x9e, 0x89, 0xfe, 0x70, 0x9f, 0x9e, 0xd9, 0x70, 0xa0, 0x60, 0xa5, 0xf0,
    0xa1, 0x7e, 0xbb, 0x70, 0xa2, 0x5c, 0x37, 0x70, 0xa3, 0x4c, 0x28, 0x70,
    0xc8, 0x6c, 0x35, 0xf0, 0xcc, 0xe7, 0x4b, 0x10, 0xcd, 0xa9, 0x17, 0x90,
    0xce, 0xa2, 0x43, 0x10, 0xcf, 0x92, 0x34, 0x10, 0xd0, 0x07, 0x5f, 0x60,
    0xd0, 0x6e, 0x42, 0x70, 0xd1, 0x72, 0x16, 0x10, 0xd2, 0x4c, 0xd2, 0xf0,
    0xd3, 0x3e, 0x31, 0x90, 0xd4, 0x49, 0xd2, 0x10, 0xd5, 0x1d, 0xf7, 0x70,
    0xd6, 0x29, 0x97, 0xf0, 0xd6, 0xeb, 0x80, 0x90, 0xd8, 0x09, 0x96, 0x10,
    0xf9, 0x33, 0xb5, 0xf0, 0xf9, 0xd9, 0xc4, 0xe0, 0xfb, 0x1c, 0xd2, 0x70,
    0xfb, 0xb9, 0xa6, 0xe0, 0xfc, 0xfc, 0xb4, 0x70, 0xfd, 0x99, 0x88, 0xe0,
    0xfe, 0xe5, 0xd0, 0xf0, 0xff, 0x82, 0xa5, 0x60, 0x00, 0xc5, 0xb2, 0xf0,
    0x01, 0x62, 0x87, 0x60, 0x02, 0x9c, 0x5a, 0x70, 0x03, 0x42, 0x77, 0x70,
    0x04, 0x85, 0x76, 0xf0, 0x05, 0x2b, 0x85, 0xe0, 0x06, 0x6e, 0x93, 0x70,
    0x07, 0x0b, 0x67, 0xe0, 0x08, 0x45, 0x3a, 0xf0, 0x08, 0xeb, 0x49, 0xe0,
    0x0a, 0x2e, 0x57, 0x70, 0x0a, 0xcb, 0x39, 0xf0, 0x0c, 0x0e, 0x39, 0x70,
    0x0c, 0xab, 0x1b, 0xf0, 0x0d, 0xe4, 0xe0, 0xf0, 0x0e, 0x8a, 0xfd, 0xf0,
    0x0f, 0xcd, 0xfd, 0x70, 0x10, 0x74, 0x1a, 0x70, 0x11, 0xad, 0xdf, 0x70,
    0x12, 0x53, 0xfc, 0x70, 0x12, 0xce, 0x97, 0xf0, 0x13, 0x4d, 0x44, 0x10,
    0x14, 0x33, 0xfa, 0x90, 0x15, 0x23, 0xeb, 0x90, 0x16, 0x13, 0xdc, 0x90,
    0x17, 0x03, 0xcd, 0x90, 0x17, 0xf3, 0xbe, 0x90, 0x18, 0xe3, 0xaf, 0x90,
    0x19, 0xd3, 0xa0, 0x90, 0x1a, 0xc3, 0x91, 0x90, 0x1b, 0xbc, 0xbd, 0x10,
    0x1c, 0xac, 0xae, 0x10, 0x1d, 0x9c, 0x9f, 0x10, 0x1e, 0x8c, 0x90, 0x10,
    0x1f, 0x7c, 0x81, 0x10, 0x20, 0x6c, 0x72, 0x10, 0x21, 0x5c, 0x63, 0x10,
    0x22, 0x4c, 0x54, 0x10, 0x23, 0x3c, 0x45, 0x10, 0x24, 0x2c, 0x36, 0x10,
    0x25, 0x1c, 0x27, 0x10, 0x26, 0x0c, 0x18, 0x10, 0x27, 0x05, 0x43, 0x90,
    0x27, 0xf5, 0x34, 0x90, 0x28, 0xe5, 0x25, 0x90, 0x29, 0xd5, 0x16, 0x90,
    0x2a, 0xc5, 0x07, 0x90, 0x2b, 0xb4, 0xf8, 0x90, 0x2c, 0xa4, 0xe9, 0x90,
    0x2d, 0x94, 0xda, 0x90, 0x2e, 0x84, 0xcb, 0x90, 0x2f, 0x74, 0xbc, 0x90,
    0x30, 0x64, 0xad, 0x90, 0x31, 0x5d, 0xd9, 0x10, 0x32, 0x72, 0xb4, 0x10,
    0x33, 0x3d, 0xbb, 0x10, 0x34, 0x52, 0x96, 0x10, 0x35, 0x1d, 0x9d, 0x10,
    0x36, 0x32, 0x78, 0x10, 0x36, 0xfd, 0x7f, 0x10, 0x38, 0x1b, 0x94, 0x90,
    0x38, 0xdd, 0x61, 0x10, 0x39, 0xfb, 0x76, 0x90, 0x3a, 0xbd, 0x43, 0x10,
    0x3b, 0xdb, 0x58, 0x90, 0x3c, 0xa6, 0x5f, 0x90, 0x3d, 0xbb, 0x3a, 0x90,
    0x3e, 0x86, 0x41, 0x90, 0x3f, 0x9b, 0x1c, 0x90, 0x40, 0x66, 0x23, 0x90,
    0x41, 0x84, 0x39, 0x10, 0x42, 0x46, 0x05, 0x90, 0x43, 0x64, 0x1b, 0x10,
    0x44, 0x25, 0xe7, 0x90, 0x45, 0x43, 0xfd, 0x10, 0x46, 0x05, 0xc9, 0x90,
    0x47, 0x23, 0xdf, 0x10, 0x47, 0xee, 0xe6, 0x10, 0x49, 0x03, 0xc1, 0x10,
    0x49, 0xce, 0xc8, 0x10, 0x4a, 0xe3, 0xa3, 0x10, 0x4b, 0xae, 0xaa, 0x10,
    0x4c, 0xcc, 0xbf, 0x90, 0x4d, 0x8e, 0x8c, 0x10, 0x4e, 0xac, 0xa1, 0x90,
    0x4f, 0x6e, 0x6e, 0x10, 0x50, 0x8c, 0x83, 0x90, 0x51, 0x57, 0x8a, 0x90,
    0x52, 0x6c, 0x65, 0x90, 0x53, 0x37, 0x6c, 0x90, 0x54, 0x4c, 0x47, 0x90,
    0x55, 0x17, 0x4e, 0x90, 0x56, 0x2c, 0x29, 0x90, 0x56, 0xf7, 0x30, 0x90,
    0x58, 0x15, 0x46, 0x10, 0x58, 0xd7, 0x12, 0x90, 0x59, 0xf5, 0x28, 0x10,
    0x5a, 0xb6, 0xf4, 0x90, 0x5b, 0xd5, 0x0a, 0x10, 0x5c, 0xa0, 0x11, 0x10,
    0x5d, 0xb4, 0xec, 0x10, 0x5e, 0x7f, 0xf3, 0x10, 0x5f, 0x94, 0xce, 0x10,
    0x60, 0x5f, 0xd5, 0x10, 0x61, 0x7d, 0xea, 0x90, 0x62, 0x3f, 0xb7, 0x10,
    0x63, 0x5d, 0xcc, 0x90, 0x64, 0x1f, 0x99, 0x10, 0x65, 0x3d, 0xae, 0x90,
    0x66, 0x08, 0xb5, 0x90, 0x67, 0x1d, 0x90, 0x90, 0x67, 0xe8, 0x97, 0x90,
    0x68, 0xfd, 0x72, 0x90, 0x69, 0xc8, 0x79, 0x90, 0x6a, 0xdd, 0x54, 0x90,
    0x6b, 0xa8, 0x5b, 0x90, 0x6c, 0xc6, 0x71, 0x10, 0x6d, 0x88, 0x3d, 0x90,
    0x6e, 0xa6, 0x53, 0x10, 0x6f, 0x68, 0x1f, 0x90, 0x70, 0x86, 0x35, 0x10,
    0x71, 0x51, 0x3c, 0x10, 0x72, 0x66, 0x17, 0x10, 0x73, 0x31, 0x1e, 0x10,
    0x74, 0x45, 0xf9, 0x10, 0x75, 0x11, 0x00, 0x10, 0x76, 0x2f, 0x15, 0x90,
    0x76, 0xf0, 0xe2, 0x10, 0x78, 0x0e, 0xf7, 0x90, 0x78, 0xd0, 0xc4, 0x10,
    0x79, 0xee, 0xd9, 0x90, 0x7a, 0xb0, 0xa6, 0x10, 0x7b, 0xce, 0xbb, 0x90,
    0x7c, 0x99, 0xc2, 0x90, 0x7d, 0xae, 0x9d, 0x90, 0x7e, 0x79, 0xa4, 0x90,
    0x7f, 0x8e, 0x7f, 0x90, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
    0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x01, 0x02, 0x01, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02,
    0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x00,
    0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x03, 0x04, 0x05,
    0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05,
    0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05,
    0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05,
    0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05,
    0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05,
    0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05,
    0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05,
    0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05,
    0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05,
    0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x00, 0x00, 0x1c, 0x20, 0x01, 0x00,
    0x00, 0x00, 0x0e, 0x10, 0x00, 0x05, 0x00, 0x00, 0x1c, 0x20, 0x01, 0x00,
    0x00, 0x00, 0x0e, 0x10, 0x00, 0x05, 0x00, 0x00, 0x1c, 0x20, 0x01, 0x00,
    0x00, 0x00, 0x0e, 0x10, 0x00, 0x05, 0x43, 0x45, 0x53, 0x54, 0x00, 0x43,
    0x45, 0x54, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00,
    0x00, 0x01, 0x01, 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11, 0xff,
    0xff, 0xff, 0xff, 0x3d, 0xbe, 0x1e, 0xcc, 0xff, 0xff, 0xff, 0xff, 0x70,
    0xbc, 0x83, 0xcc, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x37, 0xa6, 0xf0, 0xff,
    0xff, 0xff, 0xff, 0x9b, 0xd5, 0xda, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x9c,
    0xc5, 0xcb, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x9d, 0xb5, 0xbc, 0xf0, 0xff,
    0xff, 0xff, 0xff, 0x9e, 0x89, 0xfe, 0x70, 0xff, 0xff, 0xff, 0xff, 0x9f,
    0x9e, 0xd9, 0x70, 0xff, 0xff, 0xff, 0xff, 0xa0, 0x60, 0xa5, 0xf0, 0xff,
    0xff, 0xff, 0xff, 0xa1, 0x7e, 0xbb, 0x70, 0xff, 0xff, 0xff, 0xff, 0xa2,
    0x5c, 0x37, 0x70, 0xff, 0xff, 0xff, 0xff, 0xa3, 0x4c, 0x28, 0x70, 0xff,
    0xff, 0xff, 0xff, 0xc8, 0x6c, 0x35, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xcc,
    0xe7, 0x4b, 0x10, 0xff, 0xff, 0xff, 0xff, 0xcd, 0xa9, 0x17, 0x90, 0xff,
    0xff, 0xff, 0xff, 0xce, 0xa2, 0x43, 0x10, 0xff, 0xff, 0xff, 0xff, 0xcf,
    0x92, 0x34, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x07, 0x5f, 0x60, 0xff,
    0xff, 0xff, 0xff, 0xd0, 0x6e, 0x42, 0x70, 0xff, 0xff, 0xff, 0xff, 0xd1,
    0x72, 0x16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x4c, 0xd2, 0xf0, 0xff,
    0xff, 0xff, 0xff, 0xd3, 0x3e, 0x31, 0x90, 0xff, 0xff, 0xff, 0xff, 0xd4,
    0x49, 0xd2, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd5, 0x1d, 0xf7, 0x70, 0xff,
    0xff, 0xff, 0xff, 0xd6, 0x29, 0x97, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xd6,
    0xeb, 0x80, 0x90, 0xff, 0xff, 0xff, 0xff, 0xd8, 0x09, 0x96, 0x10, 0xff,
    0xff, 0xff, 0xff, 0xf9, 0x33, 0xb5, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf9,
    0xd9, 0xc4, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x1c, 0xd2, 0x70, 0xff,
    0xff, 0xff, 0xff, 0xfb, 0xb9, 0xa6, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xfc,
    0xfc, 0xb4, 0x70, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x99, 0x88, 0xe0, 0xff,
    0xff, 0xff, 0xff, 0xfe, 0xe5, 0xd0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
    0x82, 0xa5, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0xb2, 0xf0, 0x00,
    0x00, 0x00, 0x00, 0x01, 0x62, 0x87, 0x60, 0x00, 0x00, 0x00, 0x00, 0x02,
    0x9c, 0x5a, 0x70, 0x00, 0x00, 0x00, 0x00, 0x03, 0x42, 0x77, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x04, 0x85, 0x76, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x05,
    0x2b, 0x85, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6e, 0x93, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x07, 0x0b, 0x67, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x08,
    0x45, 0x3a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x08, 0xeb, 0x49, 0xe0, 0x00,
    0x00, 0x00, 0x00, 0x0a, 0x2e, 0x57, 0x70, 0x00, 0x00, 0x00, 0x00, 0x0a,
    0xcb, 0x39, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0e, 0x39, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x0c, 0xab, 0x1b, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0d,
    0xe4, 0xe0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x8a, 0xfd, 0xf0, 0x00,
    0x00, 0x00, 0x00, 0x0f, 0xcd, 0xfd, 0x70, 0x00, 0x00, 0x00, 0x00, 0x10,
    0x74, 0x1a, 0x70, 0x00, 0x00, 0x00, 0x00, 0x11, 0xad, 0xdf, 0x70, 0x00,
    0x00, 0x00, 0x00, 0x12, 0x53, 0xfc, 0x70, 0x00, 0x00, 0x00, 0x00, 0x12,
    0xce, 0x97, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x13, 0x4d, 0x44, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x14, 0x33, 0xfa, 0x90, 0x00, 0x00, 0x00, 0x00, 0x15,
    0x23, 0xeb, 0x90, 0x00, 0x00, 0x00, 0x00, 0x16, 0x13, 0xdc, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x17, 0x03, 0xcd, 0x90, 0x00, 0x00, 0x00, 0x00, 0x17,
    0xf3, 0xbe, 0x90, 0x00, 0x00, 0x00, 0x00, 0x18, 0xe3, 0xaf, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x19, 0xd3, 0xa0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1a,
    0xc3, 0x91, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xbc, 0xbd, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x1c, 0xac, 0xae, 0x10, 0x00, 0x00, 0x00, 0x00, 0x1d,
    0x9c, 0x9f, 0x10, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x8c, 0x90, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x1f, 0x7c, 0x81, 0x10, 0x00, 0x00, 0x00, 0x00, 0x20,
    0x6c, 0x72, 0x10, 0x00, 0x00, 0x00, 0x00, 0x21, 0x5c, 0x63, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x22, 0x4c, 0x54, 0x10, 0x00, 0x00, 0x00, 0x00, 0x23,
    0x3c, 0x45, 0x10, 0x00, 0x00, 0x00, 0x00, 0x24, 0x2c, 0x36, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x25, 0x1c, 0x27, 0x10, 0x00, 0x00, 0x00, 0x00, 0x26,
    0x0c, 0x18, 0x10, 0x00, 0x00, 0x00, 0x00, 0x27, 0x05, 0x43, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x27, 0xf5, 0x34, 0x90, 0x00, 0x00, 0x00, 0x00, 0x28,
    0xe5, 0x25, 0x90, 0x00, 0x00, 0x00, 0x00, 0x29, 0xd5, 0x16, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x2a, 0xc5, 0x07, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2b,
    0xb4, 0xf8, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xa4, 0xe9, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x2d, 0x94, 0xda, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2e,
    0x84, 0xcb, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x74, 0xbc, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x30, 0x64, 0xad, 0x90, 0x00, 0x00, 0x00, 0x00, 0x31,
    0x5d, 0xd9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0xb4, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x33, 0x3d, 0xbb, 0x10, 0x00, 0x00, 0x00, 0x00, 0x34,
    0x52, 0x96, 0x10, 0x00, 0x00, 0x00, 0x00, 0x35, 0x1d, 0x9d, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x36, 0x32, 0x78, 0x10, 0x00, 0x00, 0x00, 0x00, 0x36,
    0xfd, 0x7f, 0x10, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b, 0x94, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x38, 0xdd, 0x61, 0x10, 0x00, 0x00, 0x00, 0x00, 0x39,
    0xfb, 0x76, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3a, 0xbd, 0x43, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x3b, 0xdb, 0x58, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3c,
    0xa6, 0x5f, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xbb, 0x3a, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x3e, 0x86, 0x41, 0x90, 0x00, 0x00, 0x00, 0x00, 0x3f,
    0x9b, 0x1c, 0x90, 0x00, 0x00, 0x00, 0x00, 0x40, 0x66, 0x23, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x41, 0x84, 0x39, 0x10, 0x00, 0x00, 0x00, 0x00, 0x42,
    0x46, 0x05, 0x90, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x1b, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x44, 0x25, 0xe7, 0x90, 0x00, 0x00, 0x00, 0x00, 0x45,
    0x43, 0xfd, 0x10, 0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0xc9, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x47, 0x23, 0xdf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x47,
    0xee, 0xe6, 0x10, 0x00, 0x00, 0x00, 0x00, 0x49, 0x03, 0xc1, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x49, 0xce, 0xc8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4a,
    0xe3, 0xa3, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4b, 0xae, 0xaa, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x4c, 0xcc, 0xbf, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4d,
    0x8e, 0x8c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xac, 0xa1, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x4f, 0x6e, 0x6e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x50,
    0x8c, 0x83, 0x90, 0x00, 0x00, 0x00, 0x00, 0x51, 0x57, 0x8a, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x52, 0x6c, 0x65, 0x90, 0x00, 0x00, 0x00, 0x00, 0x53,
    0x37, 0x6c, 0x90, 0x00, 0x00, 0x00, 0x00, 0x54, 0x4c, 0x47, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x55, 0x17, 0x4e, 0x90, 0x00, 0x00, 0x00, 0x00, 0x56,
    0x2c, 0x29, 0x90, 0x00, 0x00, 0x00, 0x00, 0x56, 0xf7, 0x30, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x58, 0x15, 0x46, 0x10, 0x00, 0x00, 0x00, 0x00, 0x58,
    0xd7, 0x12, 0x90, 0x00, 0x00, 0x00, 0x00, 0x59, 0xf5, 0x28, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x5a, 0xb6, 0xf4, 0x90, 0x00, 0x00, 0x00, 0x00, 0x5b,
    0xd5, 0x0a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5c, 0xa0, 0x11, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x5d, 0xb4, 0xec, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5e,
    0x7f, 0xf3, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x94, 0xce, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x60, 0x5f, 0xd5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x61,
    0x7d, 0xea, 0x90, 0x00, 0x00, 0x00, 0x00, 0x62, 0x3f, 0xb7, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x63, 0x5d, 0xcc, 0x90, 0x00, 0x00, 0x00, 0x00, 0x64,
    0x1f, 0x99, 0x10, 0x00, 0x00, 0x00, 0x00, 0x65, 0x3d, 0xae, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x66, 0x08, 0xb5, 0x90, 0x00, 0x00, 0x00, 0x00, 0x67,
    0x1d, 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x67, 0xe8, 0x97, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x68, 0xfd, 0x72, 0x90, 0x00, 0x00, 0x00, 0x00, 0x69,
    0xc8, 0x79, 0x90, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xdd, 0x54, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x6b, 0xa8, 0x5b, 0x90, 0x00, 0x00, 0x00, 0x00, 0x6c,
    0xc6, 0x71, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x88, 0x3d, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x6e, 0xa6, 0x53, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6f,
    0x68, 0x1f, 0x90, 0x00, 0x00, 0x00, 0x00, 0x70, 0x86, 0x35, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x71, 0x51, 0x3c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x72,
    0x66, 0x17, 0x10, 0x00, 0x00, 0x00, 0x00, 0x73, 0x31, 0x1e, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x74, 0x45, 0xf9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x75,
    0x11, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x76, 0x2f, 0x15, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x76, 0xf0, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x00, 0x78,
    0x0e, 0xf7, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0xd0, 0xc4, 0x10, 0x00,
    0x00, 0x00, 0x00, 0x79, 0xee, 0xd9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7a,
    0xb0, 0xa6, 0x10, 0x00, 0x00, 0x00, 0x00, 0x7b, 0xce, 0xbb, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x7c, 0x99, 0xc2, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7d,
    0xae, 0x9d, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x79, 0xa4, 0x90, 0x00,
    0x00, 0x00, 0x00, 0x7f, 0x8e, 0x7f, 0x90, 0x01, 0x03, 0x02, 0x03, 0x02,
    0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02,
    0x04, 0x03, 0x04, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x04, 0x05,
    0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05, 0x04, 0x05,
    0x04, 0x05, 0x04, 0x05, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03,
    0x02, 0x03, 0x05, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
    0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
    0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
    0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
    0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
    0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
    0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
    0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
    0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06,
    0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x00,
    0x00, 0x0b, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xb4, 0x00, 0x04, 0x00,
    0x00, 0x1c, 0x20, 0x01, 0x08, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x0d, 0x00,
    0x00, 0x1c, 0x20, 0x01, 0x08, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x0d, 0x00,
    0x00, 0x1c, 0x20, 0x01, 0x08, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x0d, 0x4c,
    0x4d, 0x54, 0x00, 0x52, 0x4d, 0x54, 0x00, 0x43, 0x45, 0x53, 0x54, 0x00,
    0x43, 0x45, 0x54, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x0a, 0x43, 0x45, 0x54,
    0x2d, 0x31, 0x43, 0x45, 0x53, 0x54, 0x2c, 0x4d, 0x33, 0x2e, 0x35, 0x2e,
    0x30, 0x2c, 0x4d, 0x31, 0x30, 0x2e, 0x35, 0x2e, 0x30, 0x2f, 0x33, 0x0a,
};

// Etc/GMT
static const unsigned char ETC_GMT_DATA[] = {
    0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x47, 0x4d, 0x54, 0x00, 0x00, 0x00, 0x54, 0x5a, 0x69, 0x66,
    0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4d,
    0x54, 0x00, 0x00, 0x00, 0x0a, 0x47, 0x4d, 0x54, 0x30, 0x0a,
};

// Etc/GMT+1
static const unsigned char ETC_GMTP1_DATA[] = {
    0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0xff, 0xff, 0xf1, 0xf0,
    0x00, 0x00, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x00, 0x00, 0x00, 0x54, 0x5a,
    0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0xff, 0xff, 0xf1, 0xf0, 0x00, 0x00,
    0x47, 0x4d, 0x54, 0x2b, 0x31, 0x00, 0x00, 0x00, 0x0a, 0x3c, 0x47, 0x4d,
    0x54, 0x2b, 0x31, 0x3e, 0x31, 0x0a,
};

// Etc/GMT+2
static const unsigned char ETC_GMTP2_DATA[] = {
    0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0xff, 0xff, 0xd5, 0xd0,
    0x00, 0x00, 0x47, 0x4d, 0x54, 0x2b, 0x33, 0x00, 0x00, 0x00, 0x54, 0x5a,
    0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0xff, 0xff, 0xd5, 0xd0, 0x00, 0x00,
    0x47, 0x4d, 0x54, 0x2b, 0x33, 0x00, 0x00, 0x00, 0x0a, 0x3c, 0x47, 0x4d,
    0x54, 0x2b, 0x33, 0x3e, 0x33, 0x0a,
};

// Etc/GMT-1
static const unsigned char ETC_GMTM1_DATA[] = {
    0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0e, 0x10,
    0x00, 0x00, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x00, 0x00, 0x00, 0x54, 0x5a,
    0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00,
    0x47, 0x4d, 0x54, 0x2d, 0x31, 0x00, 0x00, 0x00, 0x0a, 0x3c, 0x47, 0x4d,
    0x54, 0x2d, 0x31, 0x3e, 0x2d, 0x31, 0x0a,
};

// Asia/Riyadh
static const unsigned char ASIA_RIYADH_DATA[] = {
    0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0xda, 0x61, 0x36, 0xb4,
    0x01, 0x00, 0x00, 0x2b, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x30, 0x00,
    0x04, 0x4c, 0x4d, 0x54, 0x00, 0x41, 0x53, 0x54, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff,
    0xff, 0xda, 0x61, 0x36, 0xb4, 0x01, 0x00, 0x00, 0x2b, 0xcc, 0x00, 0x00,
    0x00, 0x00, 0x2a, 0x30, 0x00, 0x04, 0x4c, 0x4d, 0x54, 0x00, 0x41, 0x53,
    0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x41, 0x53, 0x54, 0x2d, 0x33,
    0x0a,
};

// Asia/Saigon
static const unsigned char ASIA_SAIGON_DATA[] = {
    0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
    0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
    0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x88, 0x6f, 0x42, 0x80,
    0x91, 0x5f, 0xee, 0xd0, 0x93, 0x85, 0xb1, 0x90, 0xb7, 0x41, 0xbc, 0x00,
    0x01, 0x02, 0x03, 0x02, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x63, 0xec, 0x00, 0x04, 0x00, 0x00, 0x62, 0x70, 0x00, 0x08, 0x00, 0x00,
    0x70, 0x80, 0x00, 0x08, 0x4c, 0x4d, 0x54, 0x00, 0x53, 0x4d, 0x54, 0x00,
    0x49, 0x43, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
    0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
    0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0xff, 0xff, 0xff, 0xff,
    0x88, 0x6f, 0x42, 0x80, 0xff, 0xff, 0xff, 0xff, 0x91, 0x5f, 0xee, 0xd0,
    0xff, 0xff, 0xff, 0xff, 0x93, 0x85, 0xb1, 0x90, 0xff, 0xff, 0xff, 0xff,
    0xb7, 0x41, 0xbc, 0x00, 0x01, 0x02, 0x03, 0x02, 0x00, 0x00, 0x64, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x63, 0xec, 0x00, 0x04, 0x00, 0x00, 0x62, 0x70,
    0x00, 0x08, 0x00, 0x00, 0x70, 0x80, 0x00, 0x08, 0x4c, 0x4d, 0x54, 0x00,
    0x53, 0x4d, 0x54, 0x00, 0x49, 0x43, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x43, 0x54, 0x2d, 0x37, 0x0a,
};
// ============================================================================
//                                 HELPER FUNCTIONS
// ----------------------------------------------------------------------------
//
#ifdef BSLS_PLATFORM_OS_WINDOWS

static int loadTimezoneObsoleteFlag(bool        *isTimezoneObsoleteFlag,
                                    const HKEY&  zonesKey,
                                    const char  *timezone)
    // Load, into the specified `isTimezoneObsolete`, `true` if the specified
    // `timezone` in the registry under the specified `zonesKey` has an
    // `IsObsolete` value of 0x00000001, and `false` otherwise.  Return 0 on
    // success, and a non-zero value otherwise, with no other effect.  Note
    // that this part of the registry is described in:
    // ```
    //  http://cldr.unicode.org/development/development-process/
    //                      design-proposals/extended-windows-olson-zid-mapping
    // ```
{
    ASSERT(isTimezoneObsoleteFlag);
    ASSERT(timezone);

    HKEY zoneSubKey = {0};
    int  res        = RegOpenKeyEx(zonesKey,
                                   timezone,
                                   NULL,
                                   KEY_READ,
                                   &zoneSubKey);

    if (res != ERROR_SUCCESS) {
        ASSERT(0 == "error opening registry for some specific time zone\n");
        P(timezone);
        return -1;                                                    // RETURN
    }

    DWORD obsoleteValue     = 0;
    DWORD obsoleteValueSize = sizeof(obsoleteValue);
    res = RegQueryValueEx(zoneSubKey,
                          "IsObsolete",
                          NULL,
                          NULL,
                          reinterpret_cast<LPBYTE>(&obsoleteValue),
                          &obsoleteValueSize);
    if (ERROR_SUCCESS != res && ERROR_FILE_NOT_FOUND != res) {
        ASSERT(0 == "error querying value of `IsObsolete`\n");
        RegCloseKey(zoneSubKey);
        return -1;                                                    // RETURN
    }
    RegCloseKey(zoneSubKey);

    *isTimezoneObsoleteFlag = 0x00000001 == obsoleteValue;

    return 0;
}
static int loadTimezonesFromRegistry(vector<string> *timezones)
    // Load, into the specified `timezones`, a list of the timezone
    // identifiers found in the "Time Zones"  Registry.  Those identifiers are
    // the keys under "Time Zones".  Identifiers for obsolete time zones are
    // not loaded.  Return 0 on success, and a non-zero value otherwise.
{
    ASSERT(timezones);

    const char *registryPath =
                 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones";
    HKEY        zonesKey     = {0};
    LONG        res          = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                                            registryPath,
                                            NULL,
                                            KEY_READ,
                                            &zonesKey);

    if (res != ERROR_SUCCESS) {
        ASSERT(0 == "error opening registry: Time Zones\n");
        return -1;                                                    // RETURN
    }

    const size_t         MAX_REGKEY_NAME_LENGTH = 255;
    char         zoneBuf[MAX_REGKEY_NAME_LENGTH +   1];

    for (DWORD n = 0; ; ++n) {
        DWORD zoneLength = sizeof(zoneBuf);
        int   res        = RegEnumKeyEx(zonesKey,
                                        n,
                                        zoneBuf,
                                        &zoneLength, // in/out parameter
                                        NULL,
                                        NULL,
                                        NULL,
                                        NULL);
        if (res != ERROR_SUCCESS) {
            ASSERT(ERROR_NO_MORE_ITEMS == res);
            break;
        }

        if (0 == ::strcmp("Mid-Atlantic Standard Time", zoneBuf)) {
            continue;
        }

        bool isTimezoneObsoleteFlag;
        res = loadTimezoneObsoleteFlag(&isTimezoneObsoleteFlag,
                                       zonesKey,
                                       zoneBuf);
        if (0 != res) {
            ASSERT(0 == "error getting timezone obsolete flag");
            RegCloseKey(zonesKey);  // put this into a guard
            return -1;                                                // RETURN
        }

        if (!isTimezoneObsoleteFlag) {
            timezones->push_back(string(zoneBuf));
        }
    }

    RegCloseKey(zonesKey);  // put this into a guard
    return 0;
}
#else
typedef struct _SYSTEMTIME {
    int wYear;
    int wMonth;
    int wDayOfWeek;
    int wDay;
    int wHour;
    int wMinute;
    int wSecond;
    int wMilliseconds;
} SYSTEMTIME;

#endif

// ============================================================================
//                               MAIN PROGRAM
// ----------------------------------------------------------------------------

int main(int argc, char *argv[])
{
    int             test = argc > 1 ? atoi(argv[1]) : 0;
    bool         verbose = argc > 2;
    bool     veryVerbose = argc > 3;

    cout << "TEST " << __FILE__ << " CASE " << test << endl;

    baltzo::TestLoader    testLoader;
    baltzo::ZoneinfoCache testCache(&testLoader);
    ASSERT(0 == testLoader.setTimeZone(
                                     "GMT",
                                     reinterpret_cast<const char  *>(GMT_DATA),
                                     sizeof(GMT_DATA)));
    ASSERT(0 == testLoader.setTimeZone(
                                 "Etc/GMT",
                                 reinterpret_cast<const char  *>(ETC_GMT_DATA),
                                 sizeof(ETC_GMT_DATA)));
    ASSERT(0 == testLoader.setTimeZone(
                               "Etc/GMT+1",
                               reinterpret_cast<const char  *>(ETC_GMTP1_DATA),
                               sizeof(ETC_GMTP1_DATA)));
    ASSERT(0 == testLoader.setTimeZone(
                               "Etc/GMT+2",
                               reinterpret_cast<const char  *>(ETC_GMTP2_DATA),
                               sizeof(ETC_GMTP2_DATA)));
    ASSERT(0 == testLoader.setTimeZone(
                               "Etc/GMT-1",
                               reinterpret_cast<const char  *>(ETC_GMTM1_DATA),
                               sizeof(ETC_GMTM1_DATA)));
    ASSERT(0 == testLoader.setTimeZone(
                        "America/New_York",
                        reinterpret_cast<const char  *>(AMERICA_NEW_YORK_DATA),
                        sizeof(AMERICA_NEW_YORK_DATA)));
    ASSERT(0 == testLoader.setTimeZone(
                             "Asia/Riyadh",
                             reinterpret_cast<const char  *>(ASIA_RIYADH_DATA),
                             sizeof(ASIA_RIYADH_DATA)));
    ASSERT(0 == testLoader.setTimeZone(
                             "Asia/Saigon",
                             reinterpret_cast<const char  *>(ASIA_SAIGON_DATA),
                             sizeof(ASIA_SAIGON_DATA)));
    ASSERT(0 == testLoader.setTimeZone(
                             "Europe/Rome",
                             reinterpret_cast<const char  *>(EUROPE_ROME_DATA),
                             sizeof(EUROPE_ROME_DATA)));

    baltzo::DefaultZoneinfoCache::setDefaultCache(&testCache);

    switch (test) { case 0:
      case 4: {
        // --------------------------------------------------------------------
        // USAGE EXAMPLE
        //   Extracted from component header file.
        //
        // Concerns:
        // 1. The usage example provided in the component header file compiles,
        //    links, and runs as shown.
        //
        // Plan:
        // 1. Incorporate usage example from header into test driver, remove
        //    leading comment characters, and replace `assert` with `ASSERT`.
        //    (C-1)
        //
        // Testing:
        //   USAGE EXAMPLE
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "USAGE EXAMPLE" << endl
                          << "=============" << endl;
            {
///Usage
///-----
// In this section we show intended use of this component.
//
///Example 1: Converting Between Windows and Zoneinfo Time-Zone Identifiers
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// This example shows how to find the Zoneinfo time-zone time-zone identifier
// for a given Windows time-zone identifier, and the inverse operation.
//
// First, given the "Central Standard Time (Mexico)" Windows time-zone
// identifier, use the `getZoneinfoId` method to find the corresponding
// Zoneinfo time-zone identifier.
// ```
    int         rc;
    const char *timeZoneId;
    const char *windowsTimeZoneId;

    rc = baltzo::WindowsTimeZoneUtil::getZoneinfoId(
                                             &timeZoneId,
                                             "Central Standard Time (Mexico)");
    ASSERT(0 == rc);
    ASSERT(0 == bsl::strcmp("America/Mexico_City", timeZoneId));
// ```
// Notice that the corresponding Zoneinfo time-zone identifier is
// "America/Mexico_City".
//
// Next, use `getWindowsTimeZoneId` method to find the Windows time-zone
// identifier corresponding to "America/Mexico_City".
// ```
    rc = baltzo::WindowsTimeZoneUtil::getWindowsTimeZoneId(
                                                        &windowsTimeZoneId,
                                                        "America/Mexico_City");
    ASSERT(0 == rc);
    ASSERT(0 == bsl::strcmp("Central Standard Time (Mexico)",
                             windowsTimeZoneId));
// ```
// Notice that the time zone returned is "Central Standard Time (Mexico)", the
// original time-zone identifier.
            }
//
            {
///Example 2: Creating a `baltzo::LocalDatetime` Object on Windows
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// The following example demonstrates how to create on a Windows platform a
// `baltzo::LocalDatetime` object with the value of the current time.
//
// First, use the Windows `GetTimeZoneInformation` function to load a
// `TIME_ZONE_INFORMATION` structure.
// ```
    int                    rc;
#ifdef BSLS_PLATFORM_OS_WINDOWS
    TIME_ZONE_INFORMATION tzi;
    rc = GetTimeZoneInformation(&tzi);
    ASSERT(TIME_ZONE_ID_UNKNOWN  == rc
        || TIME_ZONE_ID_STANDARD == rc
        || TIME_ZONE_ID_DAYLIGHT == rc);
#endif
// ```
// The `StandardName` member of the structure, of type `WCHAR[32]`, contains
// the Windows time-zone identifier for Standard Time for the system's local
// time zone.
//
// Next, use the `wcstombs_s` function to convert the wide string in the
// `StandardName` member to its multi-byte equivalent in the `standardName`
// buffer, and assign the result to `localTimezone`.  Note that every Windows
// time-zone identifier mapped by this component consists entirely of 7-bit
// ASCII characters.
// ```
#ifdef BSLS_PLATFORM_OS_WINDOWS
    bsl::string localTimezone;

    {
        // Convert `StandardName` field (`WCHAR[32]`) to `bsl::string`.

        char    standardName[sizeof(tzi.StandardName) * 2 + 1] = { '\0' };
        errno_t error = wcstombs_s(NULL,
                                   standardName,
                                   sizeof(standardName),
                                   tzi.StandardName,
                                   _TRUNCATE);
        ASSERT(0 == errno);
        localTimezone.assign(standardName);
    }
#if 1 // Do not show this in component-level doc usage example.
    localTimezone.assign("Arab Standard Time");  // a value in test database
#endif
#else // Non-Windows Platforms
    bsl::string localTimezone("Arab Standard Time");
#endif
    ASSERT("Arab Standard Time" == localTimezone);
// ```
// Now, use the `getZoneinfoId` method to find the corresponding Zoneinfo
// time-zone identifier.
// ```
    const char *zoneinfoId;
    rc = baltzo::WindowsTimeZoneUtil::getZoneinfoId(&zoneinfoId,
                                                   localTimezone.c_str());
    ASSERT(0 == rc);
    ASSERT(0 == bsl::strcmp("Asia/Riyadh", zoneinfoId));
// ```
// Then, use the Windows `GetSystemTime` function to load an `SYSTEMTIME`
// structure with UTC time information.  The returned information includes
// year, month (`[1 .. 12]`), day-of-month (`[1 .. 31]`), and hour-of-day
// (`[0 .. 23]`).  Note `bdlt_date` and `bdlt_time` use the same numerical
// values to represent month, day, etc.  The range of years is different but
// practically the same as they overlap for several centuries around the
// current time.
// ```
#ifdef BSLS_PLATFORM_OS_WINDOWS
    SYSTEMTIME systemTime;
    GetSystemTime(&systemTime);
#else
    const SYSTEMTIME systemTime = {
        2012,  // wYear
           5,  // wMonth     (May)
           2,  // wDayOfWeek (Monday)
          28,  // wDay
          23,  // wHour
           0,  // wMinute
           0,  // wSecond
           0   // wMilliseconds
    };
#endif
// ```
// Finally, use these Windows SystemTime values and the calculated Zoneinfo
// time-zone identifier to set the value of a `baltzo::LocalDatetime` object.
// ```
    baltzo::LocalDatetime localDatetime;

    rc = baltzo::TimeZoneUtil::convertUtcToLocalTime(
                                    &localDatetime,
                                    zoneinfoId,
                                    bdlt::Datetime(systemTime.wYear,
                                                  systemTime.wMonth,
                                                  systemTime.wDay,
                                                  systemTime.wHour));
    ASSERT(0             == rc);
    ASSERT("Asia/Riyadh" == localDatetime.timeZoneId());
// ```
            }
      } break;
      case 3: {
        // --------------------------------------------------------------------
        // MAPPING TABLE COVERAGE
        //
        // Concerns:
        //
        // 1. The set of Windows time-zone identifiers accepted by the
        //    `getZoneId` method is useful for the business needs of Bloomberg
        //    LP.
        //
        // Plan:
        //
        // 1. The {TZDF<GO>} function provides information on a set of time
        //    zones of interest to Bloomberg customers.  Check that these are
        //    found in the registry of the Windows test platform and that they
        //    are successfully mapped to Zoneinfo time-zone identifiers.
        //
        // 2. Confirm that the current time-zone of the Windows test platform
        //    can be mapped to a Zoneinfo time-zone identifier.
        //    identifier in turn.  Expect a successfull return from each call.
        //
        // Testing:
        //   MAPPING TABLE COVERAGE
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "MAPPING TABLE COVERAGE" << endl
                          << "======================" << endl;

#ifdef BSLS_PLATFORM_OS_WINDOWS
        vector<string> timezones;
        int            rc = loadTimezonesFromRegistry(&timezones);
        ASSERT(0 == rc);

        set<string> timezoneSet(timezones.begin(), timezones.end());

        if (verbose) cout << "\nCheck Time Zones from {TZDF<GO>}" << endl;
        {

            const struct {
                int         d_line;
                const char *d_windowsTid;
                const char *d_zoneInfoTid; // known to `bsitzo_timezoneutil`.
            } DATA [] = {
          // LI  WINDOWS TIME-ZONE IDENTIFIER      ZONEINFO TID
          // --  --------------------------------  ----------------------
          {  L_, "Afghanistan Standard Time",      "Asia/Kabul"           },
          {  L_, "Alaskan Standard Time",          "America/Anchorage"    },
          {  L_, "Arabian Standard Time",          "Asia/Dubai"           },
          {  L_, "Arab Standard Time",             "Asia/Riyadh"          },
          {  L_, "Argentina Standard Time",        "America/Buenos_Aires" },
          {  L_, "Atlantic Standard Time",         "America/Halifax"      },
          {  L_, "AUS Central Standard Time",      "Australia/Darwin"     },
          {  L_, "Azores Standard Time",           "Atlantic/Azores"      },
          {  L_, "Bangladesh Standard Time",       "Asia/Dhaka"           },
          {  L_, "Canada Central Standard Time",   "America/Regina"       },
          {  L_, "Cen. Australia Standard Time",   "Australia/Adelaide"   },
          {  L_, "Central Asia Standard Time",     "Asia/Almaty"          },
          {  L_, "Central Pacific Standard Time",  "Pacific/Guadalcanal"  },
          {  L_, "Central Standard Time",          "America/Chicago"      },
          {  L_, "Central Standard Time (Mexico)", "America/Mexico_City"  },
          {  L_, "China Standard Time",            "Asia/Shanghai"        },
          {  L_, "Dateline Standard Time",         "Etc/GMT+12"           },
          {  L_, "Dateline Standard Time",         "Etc/GMT+12"           },
          {  L_, "Eastern Standard Time",          "America/New_York"     },
          {  L_, "E. Australia Standard Time",     "Australia/Brisbane"   },
          {  L_, "Egypt Standard Time",            "Africa/Cairo"         },
          {  L_, "E. South America Standard Time", "America/Sao_Paulo"    },
          {  L_, "Fiji Standard Time",             "Pacific/Fiji"         },
          {  L_, "FLE Standard Time",              "Europe/Kiev"          },
          {  L_, "GMT Standard Time",              "Europe/London"        },
          {  L_, "Hawaiian Standard Time",         "Pacific/Honolulu"     },
          {  L_, "India Standard Time",            "Asia/Kolkata"         },
          {  L_, "Iran Standard Time",             "Asia/Tehran"          },
          {  L_, "Israel Standard Time",           "Asia/Jerusalem"       },
          {  L_, "Mountain Standard Time",         "America/Denver"       },
          {  L_, "Newfoundland Standard Time",     "America/St_Johns"     },
          {  L_, "New Zealand Standard Time",      "Pacific/Auckland"     },
          {  L_, "Pacific SA Standard Time",       "America/Santiago"     },
          {  L_, "Pacific Standard Time",          "America/Los_Angeles"  },
          {  L_, "Pakistan Standard Time",         "Asia/Karachi"         },
          {  L_, "Russian Standard Time",          "Europe/Moscow"        },
          {  L_, "SA Pacific Standard Time",       "America/Bogota"       },
          {  L_, "SE Asia Standard Time",          "Asia/Bangkok"         },
          {  L_, "South Africa Standard Time",     "Africa/Johannesburg"  },
          {  L_, "Tasmania Standard Time",         "Australia/Hobart"     },
          {  L_, "Tokyo Standard Time",            "Asia/Tokyo"           },
          {  L_, "US Mountain Standard Time",      "America/Phoenix"      },
          {  L_, "UTC-02",                         "Etc/GMT+2"            },
          {  L_, "UTC-11",                         "Etc/GMT+11"           },
          {  L_, "UTC+12",                         "Etc/GMT-12"           },
          {  L_, "UTC",                            "Etc/GMT"              },
          {  L_, "Venezuela Standard Time",        "America/Caracas"      },
          {  L_, "W. Europe Standard Time",        "Europe/Berlin"        }
         };
             const int NUM_DATA = sizeof(DATA)/sizeof(*DATA);

            for (int ti = 0; ti < NUM_DATA; ++ti) {
                const int   LINE     = DATA[ti].d_line;
                const char *WINTID   = DATA[ti].d_windowsTid;
                const char *ZINFOTID = DATA[ti].d_zoneInfoTid;

                if (veryVerbose) { T_ P_(LINE)
                                      P_(WINTID)
                                      P(ZINFOTID) }

                set<string>::const_iterator itr  = timezoneSet.find(WINTID);
                ASSERT(timezoneSet.end() != itr);
            }
        }

        if (verbose) cout << "\nCheck Local Time Zone" << endl;
        {
            TIME_ZONE_INFORMATION tzi;
            int rc = GetTimeZoneInformation(&tzi);
            ASSERT(TIME_ZONE_ID_UNKNOWN  == rc
                || TIME_ZONE_ID_STANDARD == rc
                || TIME_ZONE_ID_DAYLIGHT == rc);

            string localTimezone;

            {   // Convert `StandardName` field (`WCHAR[32]`) to `bsl::string`.
                char    standardName[sizeof(tzi.StandardName) * 2 + 1] =
                                                                      { '\0' };
                errno_t error = wcstombs_s(NULL,
                                           standardName,
                                           sizeof(standardName),
                                           tzi.StandardName,
                                           _TRUNCATE);
                ASSERT(0 == errno);
                localTimezone.assign(standardName);
            }

            // See DRQS  178953830, "Coordinated Universal Time" does not
            // appear in windows time zone data.  Created a follow up ticket
            // 179195663 to track updating the mapping provided by this
            // component.
            if (localTimezone != "Coordinated Universal Time") {
                const char *timeZoneId;
                rc = baltzo::WindowsTimeZoneUtil::getZoneinfoId(
                                                        &timeZoneId,
                                                        localTimezone.c_str());
                ASSERT(0 == rc);
                if (veryVerbose) {
                    T_ P_(localTimezone) P_(timeZoneId)
                }
            }
        }
#else
        cout << "Run on Windows Platform Only" << endl;
#endif
      } break;
      case 2: {
        // --------------------------------------------------------------------
        // CLASS METHOD `getWindowsTimeZoneId`
        //
        // Concerns:
        // 1. The sorted static table mapping Zoneinfo time-zone identifiers to
        //    Windows time-zone identifiers is sorted, has a single record for
        //    each Zoneinfo time-zone identifier for each entry of the
        //    `unicode.org` table, and that entry has the correct,
        //    corresponding Windows time-zone identifier.
        //
        // 2. The table has no entries other than those described in C-1.
        //
        // 3. When given an invalid Zoneinfo time-zone identifier, the method
        //    returns a value indicating non-success, and has no other effect.
        //
        // 4. QoI: Asserted precondition violations are detected when enabled.
        //
        // Plan:
        // 1. For each Zoneinfo time-zone identifier the `DEFAULT_DATA`,
        //    confirm that the method returns success and loads the
        //    corresponding Windows time-zone identifier.  (C-1)
        //
        // 2. Compile-time asserts in the implementation check that the number
        //    of entries of the internal table matches that of `DEFAULT_DATA`.
        //    (C-2)
        //
        // 3. Use a table-driven test to confirm that for several classes of
        //    invalid Zoneinfo time-zone identifiers, the method returns a
        //    value indicating failure, and that the contents of the given load
        //    address for the Windows time-zone identifier is unchanged.  (C-3)
        //
        // 4. Verify that, in appropriate build modes, defensive checks are
        //    triggered for invalid argument values, but not triggered for
        //    adjacent valid ones (using the `BSLS_ASSERTTEST_*` macros).
        //    (C-4)
        //
        // Testing:
        //   getWindowsTimeZoneId(const char **, const char *);
        // --------------------------------------------------------------------

        if (verbose) cout
                << endl
                << "CLASS METHOD `getWindowsTimeZoneId`" << endl
                << "===================================" << endl;

        if (verbose) cout << "\nTest Good Zoneinfo Identifiers" << endl;

        const int NUM_DATA                     = DEFAULT_NUM_DATA;
        const DefaultDataRow (&DATA)[NUM_DATA] = DEFAULT_DATA;

        for (int ti = 0; ti < NUM_DATA; ++ti) {
            const int   LINE        = DATA[ti].d_line;
            const char *GIVEN_ID    = DATA[ti].d_zoneinfoId;
            const char *EXPECTED_ID = DATA[ti].d_windowsId;

            if (veryVerbose) { T_ P_(LINE) P_(GIVEN_ID) P(EXPECTED_ID) }

            const char *winId;
            int         rc = Obj::getWindowsTimeZoneId(&winId, GIVEN_ID);
            LOOP2_ASSERT(LINE, rc, 0 == rc);
            LOOP4_ASSERT(LINE, GIVEN_ID, EXPECTED_ID, winId,
                         0 == bsl::strcmp(EXPECTED_ID, winId));
        }

        if (verbose) cout << "\nFailure Testing." << endl;
        {
             const struct {
                 int         d_line;
                 const char *d_badZoneinfoId;
             } DATA [] = {
                 // LINE  BAD ZONEINFO ID
                 // ----  ----------------------------------------
                  { L_,   "aBelowLowerBoundofValidInputs"          },
                  { L_,   "America/Mexico_City amidValidInputs"    },
                  { L_,   "ZZZZZZZZZZAboveUpperBoundofValidInputs" }
             };
             const int NUM_DATA = sizeof(DATA)/sizeof(*DATA);

             for (int ti = 0; ti < NUM_DATA; ++ti) {
                 const int   LINE     = DATA[ti].d_line;
                 const char *BAD_ID   = DATA[ti].d_badZoneinfoId;
                 const char *EXP_ADDR = (const char *)&ti;

                 if (veryVerbose) { T_ P_(LINE)
                                       P_(BAD_ID)
                                       P((const void *)EXP_ADDR) }

                 const char *winId = EXP_ADDR;
                 int         rc    = Obj::getZoneinfoId(&winId, BAD_ID);
                 LOOP2_ASSERT(LINE, BAD_ID,           0        != rc);
                 LOOP2_ASSERT(LINE, (const void *)EXP_ADDR, EXP_ADDR == winId);
             }
        }

        if (verbose) cout << "\nNegative Testing." << endl;
#ifdef BDE_BUILD_TARGET_EXC
        {
            bsls::AssertTestHandlerGuard hG;

            const char  *tzId = "America/Mexico_City";
            const char *winId;

            ASSERT_PASS(Obj::getWindowsTimeZoneId(&winId, tzId));
            ASSERT_FAIL(Obj::getWindowsTimeZoneId(0,      tzId));
            ASSERT_FAIL(Obj::getWindowsTimeZoneId(&winId, 0));
            ASSERT_FAIL(Obj::getWindowsTimeZoneId(0,      0));
        }
#else  // BDE_BUILD_TARGET_EXC
        if (verbose) cout << "\nDISABLED in this (non-exception) build mode."
                          << endl;
#endif // BDE_BUILD_TARGET_EXC
      } break;
      case 1: {
        // --------------------------------------------------------------------
        // CLASS METHOD `getZoneinfoId`
        //
        // Concerns:
        // 1. The sorted static table mapping Windows time-zone identifiers to
        //    Zoneinfo time-zone identifiers is sorted, has a single record for
        //    each Windows time-zone identifier for each entry of the
        //    `unicode.org` table, and that entry has the correct,
        //    corresponding Zoneinfo time-zone identifier.
        //
        // 2. The table has no entries other than those described in C-1.
        //
        // 3. When given an invalid Windows time-zone identifier, the method
        //    returns a value indicating non-success, and has no other effect.
        //
        // 4. QoI: Asserted precondition violations are detected when enabled.
        //
        // Plan:
        // 1. For each Windows time-zone identifier the `DEFAULT_DATA`, confirm
        //    that the method returns success and loads the corresponding
        //    Zoneinfo time-zone identifier.  (C-1)
        //
        // 2. Compile-time asserts in the implementation check that the number
        //    of entries of the internal table matches that of `DEFAULT_DATA`.
        //    (C-2)
        //
        // 3. Use a table-driven test to confirm that for several classes of
        //    invalid Windows time-zone identifiers, the method returns a value
        //    indicating failure, and that the contents of the given load
        //    address for the Zoneinfo time-zone identifier is unchanged.
        //    (C-3)
        //
        // 4. Verify that, in appropriate build modes, defensive checks are
        //    triggered for invalid argument values, but not triggered for
        //    adjacent valid ones (using the `BSLS_ASSERTTEST_*` macros).
        //    (C-4)
        //
        // Testing:
        //   getZoneinfoId(const char **, const char *);
        // --------------------------------------------------------------------

        if (verbose) cout
                << endl
                << "CLASS METHOD `getZoneinfoId`" << endl
                << "============================" << endl;

        if (verbose) cout << "\nTest Good Windows Time-Zone Identifiers"
                          << endl;

        const int NUM_DATA                     = DEFAULT_NUM_DATA;
        const DefaultDataRow (&DATA)[NUM_DATA] = DEFAULT_DATA;

        for (int ti = 0; ti < NUM_DATA; ++ti) {
            const int   LINE        = DATA[ti].d_line;
            const char *GIVEN_ID    = DATA[ti].d_windowsId;
            const char *EXPECTED_ID = DATA[ti].d_zoneinfoId;

            if (veryVerbose) { T_ P_(LINE) P_(GIVEN_ID) P(EXPECTED_ID) }

            const char *tzId;
            int         rc = Obj::getZoneinfoId(&tzId, GIVEN_ID);
            LOOP2_ASSERT(LINE, rc, 0 == rc);
            LOOP4_ASSERT(LINE, GIVEN_ID, EXPECTED_ID, tzId,
                         0 == bsl::strcmp(EXPECTED_ID, tzId));
        }

        if (verbose) cout << "\nFailure Testing." << endl;
        {
             const struct {
                 int         d_line;
                 const char *d_badWinId;
             } DATA [] = {
                 // LINE  BAD WINDOWS ID
                 // ----  ------------------------------------------------
                  { L_,   "aBelowLowerBoundofValidInputs"                  },
                  { L_,   "Central Standard Time (Mexico) amidValidInputs" },
                  { L_,   "ZZZZZZZAboveUpperBoundofValidInputs"            }
             };
             const int NUM_DATA = sizeof(DATA)/sizeof(*DATA);

             for (int ti = 0; ti < NUM_DATA; ++ti) {
                 const int   LINE     = DATA[ti].d_line;
                 const char *BAD_ID   = DATA[ti].d_badWinId;
                 const char *EXP_ADDR = (const char *)&ti;

                 if (veryVerbose) { T_ P_(LINE)
                                       P_(BAD_ID)
                                       P((const void *)EXP_ADDR) }

                 const char *tzId = EXP_ADDR;
                 int         rc   = Obj::getZoneinfoId(&tzId, BAD_ID);
                 LOOP2_ASSERT(LINE, BAD_ID,           0        != rc);
                 LOOP2_ASSERT(LINE, (const void *)EXP_ADDR, EXP_ADDR == tzId);
             }
        }

        if (verbose) cout << "\nNegative Testing." << endl;
#ifdef BDE_BUILD_TARGET_EXC
        {
            bsls::AssertTestHandlerGuard hG;

            const char *winId = "Central Standard Time (Mexico)";
            const char *tzId;

            ASSERT_PASS(Obj::getZoneinfoId(&tzId, winId));
            ASSERT_FAIL(Obj::getZoneinfoId(0,     winId));
            ASSERT_FAIL(Obj::getZoneinfoId(&tzId, 0));
            ASSERT_FAIL(Obj::getZoneinfoId(0,     0));
        }
#else  // BDE_BUILD_TARGET_EXC
        if (verbose) cout << "\nDISABLED in this (non-exception) build mode."
                          << endl;
#endif // BDE_BUILD_TARGET_EXC
      } break;
#ifdef BSLS_PLATFORM_OS_WINDOWS
      case -1: {
        // --------------------------------------------------------------------
        // WINDOWS PLATFORM CHECKS
        //
        // Concerns:
        //
        // 1. Each non-obsolete Windows time-zone identifier on the Windows
        //    platforms of interest can be mapped to a Zoneinfo identifier by
        //    the `getZoneinfoId` method.
        //
        // Plan:
        //
        // 1. Obtain the set of Windows time-zone identifiers from the Windows
        //    registry using the `loadTimezonesFromRegistry` helper function.
        //
        // 2. Call the `getZoneinfoId` method for each Windows time-zone
        //    identifier in turn.  Expect a successfull return from each call.
        //
        // Testing:
        //   WINDOWS PLATFORM CHECKS
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "WINDOWS PLATFORM CHECKS" << endl
                          << "=======================" << endl;

        vector<string> timezones;
        int            rc = loadTimezonesFromRegistry(&timezones);
        ASSERT(0 == rc);

        for (vector<string>::const_iterator cur  = timezones.begin(),
                                            end  = timezones.end();
                                            end != cur; ++cur) {
            const char *winId = cur->c_str();
            if (veryVerbose) { P(winId); }

            const char *tzId;
            int         rc = Obj::getZoneinfoId(&tzId, winId);
            LOOP_ASSERT(winId, 0 == rc);
        }
      } break;
#endif
      default: {
        cerr << "WARNING: CASE `" << test << "' NOT FOUND." << endl;
        testStatus = -1;
      }
    }

    if (testStatus > 0) {
        cerr << "Error, non-zero test status = " << testStatus << "." << endl;
    }
    return testStatus;
}

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
